Просмотр текстового файла построчно на C

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

  int main (char * argc, char * argv []) {const char * filename = argv [0];  ФАЙЛ * файл = fopen (имя файла, "r");  char * line = NULL;  while (! feof (файл)) {sscanf (строка, имя файла, "% s");  printf ("% s  n", строка);  } return 1;}  

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


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

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

Итак

  #include  int main (int argc, char * argv []) {char const * const fileName = argv [1]; /* следует проверить, что argc> 1 */FILE * file = fopen (fileName, "r"); /* должен проверить результат */char line [256];  while (fgets (line, sizeof (line), file)) {/* обратите внимание, что fgets не удаляет завершающий  n, проверка его наличия позволит обрабатывать строки длиннее этого sizeof (line) */printf ("% s  ", линия);  }/* здесь можно проверить feof, чтобы различить сбой eof и io - например, тайм-аут сети */fclose (file);  return 0;}  

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

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

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


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

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

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


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


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


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

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

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

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

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

  #define BUFFER_MAX_LENGTH 1024int main (int argc, char * argv []) {FILE * file = NULL;  строка символов [BUFFER_MAX_LENGTH];  int tempChar;  беззнаковый int tempCharIdx = 0U;  если (argc == 2) file = fopen (argv [1], "r");  else {fprintf (stderr, "ошибка: неправильное количество аргументов  n" "использование:% s текстовый файл  n", argv [0]);  вернуть EXIT_FAILURE;  } если (! файл) {fprintf (stderr, "ошибка: не удалось открыть текстовый файл:% s  n", argv [1]);  вернуть EXIT_FAILURE;  }/* получить символ из указателя файла */while (tempChar = fgetc (file)) {/* избежать ошибки переполнения буфера */if (tempCharIdx == BUFFER_MAX_LENGTH) {fprintf (stderr, "error: строка слишком длинная.  увеличить BUFFER_MAX_LENGTH.  n ");  вернуть EXIT_FAILURE;  }/* значение тестового символа */if (tempChar == EOF) {line [tempCharIdx] = ' 0';  fprintf (stdout, "% s  n", строка);  перерыв;  } иначе, если (tempChar == ' n') {строка [tempCharIdx] = ' 0';  tempCharIdx = 0U;  fprintf (stdout, "% s  n", строка);  Продолжать;  } еще строка [tempCharIdx ++] = (char) tempChar;  } return EXIT_SUCCESS;}  

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

  #define BUFFER_MAX_LENGTH 1024int  main (int argc, char * argv []) {ФАЙЛ * файл = NULL;  строка символов [BUFFER_MAX_LENGTH];  int tempChar;  беззнаковый int tempCharIdx = 0U;  char * dynamicLine = NULL;  если (argc == 2) file = fopen (argv [1], "r");  else {fprintf (stderr, "ошибка: неправильное количество аргументов  n" "использование:% s текстовый файл  n", argv [0]);  вернуть EXIT_FAILURE;  } если (! файл) {fprintf (stderr, "ошибка: не удалось открыть текстовый файл:% s  n", argv [1]);  вернуть EXIT_FAILURE;  } while (tempChar = fgetc (file)) {/* избежать ошибки переполнения буфера */if (tempCharIdx == BUFFER_MAX_LENGTH) {fprintf (stderr, "error: строка слишком длинная. Увеличьте BUFFER_MAX_LENGTH.  n");  вернуть EXIT_FAILURE;  }/* значение тестового символа */if (tempChar == EOF) {line [tempCharIdx] = ' 0';  dynamicLine = strdup (строка);  fprintf (stdout, "% s  n", dynamicLine);  бесплатно (dynamicLine);  dynamicLine = NULL;  перерыв;  } иначе, если (tempChar == ' n') {строка [tempCharIdx] = ' 0';  tempCharIdx = 0U;  dynamicLine = strdup (строка);  fprintf (стандартный вывод, "% s  n", dynamicLine);  бесплатно (dynamicLine);  dynamicLine = NULL;  Продолжать;  } еще строка [tempCharIdx ++] = (char) tempChar;  } return EXIT_SUCCESS;}  


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

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

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

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

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

  #define BUFFER_MAX_LENGTH 1024int main (int argc, char * argv []) {FILE * file = NULL;  строка символов [BUFFER_MAX_LENGTH];  int tempChar;  беззнаковый int tempCharIdx = 0U;  если (argc == 2) file = fopen (argv [1], "r");  else {fprintf (stderr, "ошибка: неправильное количество аргументов  n" "использование:% s текстовый файл  n", argv [0]);  вернуть EXIT_FAILURE;  } если (! файл) {fprintf (stderr, "ошибка: не удалось открыть текстовый файл:% s  n", argv [1]);  вернуть EXIT_FAILURE;  }/* получить символ из указателя файла */while (tempChar = fgetc (file)) {/* избежать ошибки переполнения буфера */if (tempCharIdx == BUFFER_MAX_LENGTH) {fprintf (stderr, "error: строка слишком длинная.  увеличить BUFFER_MAX_LENGTH.  n "); return EXIT_FAILURE;}/* значение тестового символа */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 [] после того, как он заполнится вводимой строкой. Вы должны бесплатно эта дублированная строка, как только вы закончите с ней, или вы получите утечку памяти:

  #define BUFFER_MAX_LENGTH 1024int main (int argc, char * argv [])  {FILE * file = NULL; строка символов [BUFFER_MAX_LENGTH]; int tempChar; unsigned int tempCharIdx = 0U; char * dynamicLine = NULL; if (argc == 2) file = fopen (argv [1], "r"); else  {fprintf (stderr, "ошибка: неправильное количество аргументов  n" "использование:% s текстовый файл  n", argv [0]); вернуть EXIT_FAILUR  E;  } если (! файл) {fprintf (stderr, "ошибка: не удалось открыть текстовый файл:% s  n", argv [1]);  вернуть EXIT_FAILURE;  } while (tempChar = fgetc (file)) {/* избежать ошибки переполнения буфера */if (tempCharIdx == BUFFER_MAX_LENGTH) {fprintf (stderr, "error: строка слишком длинная. Увеличьте BUFFER_MAX_LENGTH.  n");  вернуть EXIT_FAILURE;  }/* значение тестового символа */if (tempChar == EOF) {line [tempCharIdx] = ' 0';  dynamicLine = strdup (строка);  fprintf (стандартный вывод, "% s  n", dynamicLine);  бесплатно (dynamicLine);  dynamicLine = NULL;  перерыв;  } иначе, если (tempChar == ' n') {строка [tempCharIdx] = ' 0';  tempCharIdx = 0U;  dynamicLine = strdup (строка);  fprintf (стандартный вывод, "% s  n", dynamicLine);  бесплатно (dynamicLine);  dynamicLine = NULL;  Продолжать;  } еще строка [tempCharIdx ++] = (char) tempChar;  } return EXIT_SUCCESS;}  

Оцените статью
techsly.ru
Добавить комментарий