2016-03-06 5 views
2

Я пытаюсь назначить значения из массива, содержащего все строки, в массив структур, где некоторые из членов структуры являются целыми числами. Однако, как я пытался это сделать, это вызывает некоторое неопределенное поведение. Как ниже код генерирует следующее:Назначение значений из массива массиву структур

0 surname ▒▒ 
1 forename & 
2 id 0 

, когда он должен сказать

0 surname Boatswain 
1 forename Michael Jr 
2 id 109993267 

Я не совсем уверен, что случилось с тем, как я присвоенным этими значениями, хотя.

Код:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

//There are 7 values for each student 
#define VALUES 7 

struct Students{ 
    int term; 
    int id; // NEED TO GENERATE ERROR IF WRONG NUM OF CHARACTERS 
    char surname[15]; 
    char forename[15]; 
    char subject[3]; 
    int catnum; 
    char section[3]; 
}; 

int main(int argc, char *argv[]){ 

//Get contents of input file 
    unsigned char filename; 
    printf("Enter the input file name: \n"); 
    scanf("%s", &filename); 
    FILE *file = fopen(&filename, "r"); 
    int filesize=0; 
    fseek(file, 0L, SEEK_END); 
    filesize = ftell(file); 
    fseek(file, 0L, SEEK_SET); 
    char *contents = malloc(filesize+1); 
    size_t size=fread(contents,1,filesize,file); 
    contents[size]=0; // what does all this do exactly? 

//Get number of lines in input file 
    int total_line = 0; 
    const char *str; 
    for(str = contents; *str; ++str) 
    total_line += *str == '\n'; 

//Tokenize string 
    int n=0,nn; 
    char *b[VALUES*total_line]; 
    char *ds=strdup(contents); 
    b[n]=strtok(ds, ",=\"\r\n\""); 
    while(b[n] && n<((VALUES*total_line)-1)) b[++n]=strtok(NULL, ",=\"\r\n\""); 
    //for(nn=0; nn<=n; ++nn) printf("%s %d ", b[nn], nn); 
    //putchar('\n'); 
    free(ds); 

    struct Students record[total_line]; 

    int i, j; 
    for(i=0;i++;i<total_line){ 
    for(j=0;j++;j<VALUES){ 
     int n=(7*i)+j; 
     record[i].term=atoi(b[n]); 
     record[i].id=atoi(b[n]); 
     strcpy(record[i].surname, b[n]); 
     strcpy(record[i].forename, b[n]); 
     strcpy(record[i].subject, b[n]); 
     record[i].catnum=atoi(b[n]); 
     strcpy(record[i].section, b[n]); 
    } 
    } 

// try printing some values here 
    printf("0 surname %s\n",record[0].surname); 
    printf("1 forename %s\n",record[1].forename); 
    printf("2 id %d\n", record[2].id); 

    free(contents); 
    return 0; 
} 

входного файла:

1301,107515018,"Boatswain","Michael R.",CSE, 230,="R01" 
1301,109993269,"Castille","Michael Jr",CSE, 230,="R03" 
1301,109993267,"Castille","Janice",CSE, 230,="R03" 

Заранее спасибо за помощь!

Редактировать: В чем проблема при изменении цикла for так?

for(i=0;i<total_line;i++) { 
    record[i].term=atoi(b[(7*i)]); 
    record[i].id=atoi(b[(7*i)+1]); 
    strcpy(record[i].surname, b[(7*i)+2]); 
    strcpy(record[i].forename, b[(7*i)+3]); 
    strcpy(record[i].subject, b[(7*i)+4]); 
    record[i].catnum=atoi(b[(7*i)+5]); 
    strcpy(record[i].section, b[(7*i)+6]); 
} 

Редактировать: Я получил его на работу. Просто нужно изменить цикл for-while на цикл while. Edit2: ohh У меня были i ++ и i total_line. Derp. теперь исправлено. Ну, я думаю, это решает эту тайну.

+0

Одна ключевая идея программирования: ** абстракция **. Это означает скрытие сложного материала за простыми описательными именами. Таким образом, основной (основной) инструмент в C является * функцией *. Попытайтесь разложить свою проблему на более мелкие подзадачи. –

+1

'unsigned char filename;' означает * один символ *. Затем вы записываете 'scanf ("% s ", & filename);' который читает много символов. Это приводит к переполнению буфера с непредсказуемыми последствиями. –

ответ

2

В вашей петле for(j=0;j++;j<VALUES) вы конвертируете то же самое b[n] несколько раз. Скорее всего, вам не нужен этот цикл, но вместо этого нужно преобразовать b[n++].

+0

Спасибо за помощь! Я смущен, почему этот цикл не работает. 0-6 следует перейти к записи [0], поэтому 7 * i = 0 и j добавляет от 0 до 6 на нее, давая запись [0] 0-6 и т. Д. Для записи [1], получая 7-13, и запись [2] получает 14-20. По крайней мере, так я и думал. Я также не понимаю синтаксис, который вы рекомендуете. Комментируя j-цикл и меняя b [n] на b [n ++] (например, 'record [i] .term = atoi (b [n ++]);'), не работает. – Chylomicron

+0

Что бы я сделал в такой ситуации, чтобы начать отображать отладочные материалы на экране. Например, и сделайте что-то подобное для каждого оператора цикла: 'record [i] .term = atoi (b [n]); printf («Сохраненное целочисленное значение% d в записи [i =% d] .term \ n", atoi (b [n]), i); 'Это должно дать понять, что происходит. –

+0

ohh pssh. теперь, когда я вижу это, я просто чувствую себя глупо. Спасибо еще раз за помощь! – Chylomicron

2

Предварительно, эта линия (которая, по-видимому вы уже нашли подозрительный) ...

contents[size]=0; // what does all this do exactly? 

... добавляет строку терминатор после байтов, считанных из файла, так что все может быть безопасно интерпретируется как одна большая строка C.

@DavetheSax достоверно следит за индексами ваших жетонов. Эта проблема не вызывает ошибки , но полученное поведение, конечно же, не то, что вы хотели.

Однако у вас действительно есть неопределенное поведение в вашей программе. Вы заполняете массив b путем обмана contents на ds, а затем на токенизацию ds с strtok(). Это само по себе хорошо, но необходимо, только если вам нужно сохранить contents, поскольку он был первоначально прочитан, чего вы, вероятно, не знаете. Однако после токенизации вы освобождаете ds. Это, опять же, само по себе не проблема, но это делает недействительными все указатели маркеров, которые вы только что вычислили, потому что они указывают на ранее выделенную память для ds (из которой они были маркированы). Вам нужно сохранить это до тех пор, пока вы не проанализируете токены. Выделение этих указателей токенов после освобождения пространства, в которое они указывают, создает UB.

Как правило, нельзя прогнозировать UB (иначе это не будет UB). Тем не менее, конкретные результаты, о которых вы сообщаете, кажутся маловероятным проявлением, поэтому, возможно, здесь все больше происходит.

+0

Спасибо! Это очень хорошие вопросы о 'contents' и' ds'. Я нашел код в другом месте в stackoverflow, и я не очень хорошо его модифицировал для своей программы, я думаю. Как мне следует использовать индексы? Я не совсем уверен, что в настоящее время не так с ними – Chylomicron

+0

@Chylomicron, в исходной версии вашего внутреннего цикла, вы назначаете каждое поле из 'b [n]', не обновляя 'n' между ними. Ваш пересмотренный не-вложенный цикл выглядит намного лучше. –

+0

Это выглядит лучше, но по-прежнему не работает по какой-то причине: x И почему-то печатные заявления не работают, что затрудняет отладку. Я использую gcc-компилятор, если это помогает. – Chylomicron

Смежные вопросы