Чтение файла с разделителями-запятыми с помощью fgets () и strtok () - PullRequest
1 голос
/ 02 декабря 2010

У меня есть текстовый файл с тремя полями, разделенными запятой.Пример содержимого моего текстового файла: 12345, новичок в истинном программировании, BS ME. Чтобы загрузить файл в программу, я использовал следующий код .... Моя проблема в том, что иногда код работает, а иногда нет (нетпоявляется сообщение об ошибке, программа просто закрывается и не продолжается).я также заметил, что текстовый файл пуст (ничего не написано), он автоматически закрывается и не продолжается.Ваша помощь будет высоко оценена.Спасибо!

int read(){
     FILE *stream = NULL;
     int ctr;
     char linebuffer[45];
     char delims[]=", ";
     char *number[3];
     char *token = NULL;
     stream = fopen("student.txt", "rt");
     if (stream == NULL) stream = fopen("student.txt", "wt");
     else {
          printf("\nReading the student list directory. Wait a moment please...");
          while(!feof(stream)){            
                ctr=0;
                fgets(linebuffer, 46, stream);
                token = strtok(linebuffer, delims);
                while(token != NULL){
                  number[ctr] = linebuffer;
                  token = strtok(NULL, delims); 
                  ctr++;
                }
          recordCtr++;                      
          }                     
     recordCtr--;
     }
     fclose(stream);
}    

Ответы [ 3 ]

2 голосов
/ 02 декабря 2010

Вы никогда не копируете token, как только нашли его. Вы не можете скопировать linebuffer, так как данные там будут перезаписаны при загрузке следующей строки.

Эта строка:

number[ctr] = linebuffer;

должен ссылаться на token для сохранения последнего найденного токена, но это не так. Вероятно, следует читать что-то вроде 1 :

strcpy(number[ctr], token);

но тогда вам придется изменить объявление, чтобы убедиться, что есть место:

char number[3][32];

Очевидно, это приводит к риску переполнения буфера, если есть очень длинный токен, который он не подходит. Как лучше всего справиться с этим, оставленным в качестве упражнения. :)

1 Почему временный вектор называется «число», когда он используется для хранения двух чисел и одной строки (имя) вне меня.

1 голос
/ 02 декабря 2010

Пусть покупатель остерегается.

strtok может иметь некоторые крайние случаи, о которых нужно беспокоиться.

"один, два, три" даст 3 жетона.

«один, три» даст 2 токена.

1 голос
/ 02 декабря 2010

Ваш fgets() вызов должен указать 45 в качестве размера или вы переполните буфер, когда fgets записывает терминатор NULL.Это установит строку «delims» в качестве пустой строки.

Также вы не возвращаете никакого значения, даже если в объявлении функции указано, что он возвращает int.

Я не знаю, чтоопределение вашего "struct student" такое, но вы можете переполнять буферы при использовании strcpy().Также вы уменьшаете "recordCtr".Зачем?Почему вы открываете файл для записи, если не можете открыть его для записи?Зачем?Если это тоже не удается, вы вызываете fclose для NULL-указателя.Я сомневаюсь, что это очень помогает.

Я только что заметил, что вы не инициализируете "число".Если вы не получите три числа в первой строке, вы получите strcpy() из неинициализированного указателя.Вероятно, он имеет значение NULL, поэтому программа будет иметь ошибку по умолчанию.

Также у вас есть массив размера 3, но если в строке, которую вы читаете, более 3 полей, разделенных запятыми, вы переполните массив.1013 * Возможно, есть и много других ошибок.

Многие программисты просто не могут быть обеспокоены выполнением всех хороших практик кодирования, таких как проверка возвращаемых значений, инициализация переменных и так далее.Они часто заканчивают с таким кодом.Если вы хотите быть действительно хорошим программистом, попробуйте привыкнуть делать все эти вещи или, по крайней мере, всегда думать о том, нужно вам это или нет.

В этом коде так много потенциальных ошибок,Что происходит, если длина строки превышает 45 символов?Вы не раздеваете новые строки.Вы не конвертируете строки в числа (хотя число [1] выглядит как строковые данные, так зачем хранить их в массиве с именем «числа»?), Или проверяете, что fgets действительно вернул какие-либо данные, или проверьте, сколько частей данных выполучить.

...