Прохождение текстового файла по строке в C

Я работал над небольшим упражнением для своего classа CIS и очень смущен методами, которые C использует для чтения из файла. Все, что мне действительно нужно сделать, это прочитать файл по строкам и использовать информацию, собранную из каждой строки, чтобы сделать несколько манипуляций. Я пробовал использовать метод getline и другие без везения. Мой код в настоящее время выглядит следующим образом:

int main(char *argc, char* argv[]){ const char *filename = argv[0]; FILE *file = fopen(filename, "r"); char *line = NULL; while(!feof(file)){ sscanf(line, filename, "%s"); printf("%s\n", line); } return 1; } 

Прямо сейчас я получаю seg-ошибку в методе sscanf, и я не уверен, почему. Я полный C noob и просто задаюсь вопросом, есть ли какая-то большая картина, которую я отсутствовал. Спасибо

Так много проблем в стольких строках. Вероятно, я забыл:

  • argv [0] – это имя программы, а не первый аргумент;
  • если вы хотите прочитать переменную, вам нужно выделить ее память
  • один никогда не зацикливается на feof, одна петля на функции IO до тех пор, пока она не сработает, feof затем служит для определения причины неудачи,
  • sscanf существует, чтобы проанализировать строку, если вы хотите проанализировать файл, используйте fscanf,
  • «% s» остановится в первом пространстве как формат семейства? scanf
  • для чтения строки стандартная функция – fgets,
  • возврат 1 из отказа основного средства

Так

 #include  int main(int argc, char* argv[]) { char const* const fileName = argv[1]; /* should check that argc > 1 */ FILE* file = fopen(fileName, "r"); /* should check the result */ char line[256]; while (fgets(line, sizeof(line), file)) { /* note that fgets don't strip the terminating \n, checking its presence would allow to handle lines longer that sizeof(line) */ printf("%s", line); } /* may check feof here to make a difference between eof and io failure -- network timeout for instance */ fclose(file); return 0; } 

Чтобы прочитать строку из файла, вы должны использовать функцию fgets : она считывает строку из указанного файла до символа новой строки или EOF .

Использование sscanf в вашем коде не будет работать вообще, поскольку вы используете filename как строку формата для чтения из line в константный строковый литерал %s .

Причина SEGV заключается в том, что вы записываете в нераспределенную память, на которую указывает line .

Предположим, что вы имеете дело с каким-либо другим разделителем, таким как вкладка \t , вместо \n новой строки.

Более общий подход к разделителям – это использование getc() , которое захватывает по одному символу за раз.

Обратите внимание, что getc() возвращает int , так что мы можем проверить равенство с EOF .

Во-вторых, мы определяем line[BUFFER_MAX_LENGTH] массива line[BUFFER_MAX_LENGTH] типа char , чтобы сохранить до BUFFER_MAX_LENGTH-1 символов в стеке (мы должны сохранить этот последний символ для символа терминатора \0 ).

Использование массива позволяет избежать необходимости использования malloc и free создавать указатель символа правильной длины в куче.

 #define BUFFER_MAX_LENGTH 1024 int main(int argc, char* argv[]) { FILE *file = NULL; char line[BUFFER_MAX_LENGTH]; int tempChar; unsigned int tempCharIdx = 0U; if (argc == 2) file = fopen(argv[1], "r"); else { fprintf(stderr, "error: wrong number of arguments\n" "usage: %s textfile\n", argv[0]); return EXIT_FAILURE; } if (!file) { fprintf(stderr, "error: could not open textfile: %s\n", argv[1]); return EXIT_FAILURE; } /* get a character from the file pointer */ while(tempChar = fgetc(file)) { /* avoid buffer overflow error */ if (tempCharIdx == BUFFER_MAX_LENGTH) { fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n"); return EXIT_FAILURE; } /* test character value */ if (tempChar == EOF) { line[tempCharIdx] = '\0'; fprintf(stdout, "%s\n", line); break; } else if (tempChar == '\n') { line[tempCharIdx] = '\0'; tempCharIdx = 0U; fprintf(stdout, "%s\n", line); continue; } else line[tempCharIdx++] = (char)tempChar; } return EXIT_SUCCESS; } 

Если вы должны использовать char * , то вы все равно можете использовать этот код, но вы strdup() массив line[] , как только он будет заполнен значением ввода строки. Вы должны free эту дублируемую строку, как только вы закончите с ней, или вы получите утечку памяти:

 #define BUFFER_MAX_LENGTH 1024 int main(int argc, char* argv[]) { FILE *file = NULL; char line[BUFFER_MAX_LENGTH]; int tempChar; unsigned int tempCharIdx = 0U; char *dynamicLine = NULL; if (argc == 2) file = fopen(argv[1], "r"); else { fprintf(stderr, "error: wrong number of arguments\n" "usage: %s textfile\n", argv[0]); return EXIT_FAILURE; } if (!file) { fprintf(stderr, "error: could not open textfile: %s\n", argv[1]); return EXIT_FAILURE; } while(tempChar = fgetc(file)) { /* avoid buffer overflow error */ if (tempCharIdx == BUFFER_MAX_LENGTH) { fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n"); return EXIT_FAILURE; } /* test character value */ if (tempChar == EOF) { line[tempCharIdx] = '\0'; dynamicLine = strdup(line); fprintf(stdout, "%s\n", dynamicLine); free(dynamicLine); dynamicLine = NULL; break; } else if (tempChar == '\n') { line[tempCharIdx] = '\0'; tempCharIdx = 0U; dynamicLine = strdup(line); fprintf(stdout, "%s\n", dynamicLine); free(dynamicLine); dynamicLine = NULL; continue; } else line[tempCharIdx++] = (char)tempChar; } return EXIT_SUCCESS; } 

В дополнение к другим ответам, в недавней библиотеке C (совместим с Posix 2008), вы можете использовать getline . См. Этот ответ (к соответствующему вопросу).