Странное поведение при подсчете строк из файла - PullRequest
0 голосов
/ 22 февраля 2012

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

Это код:

FILE *file = fopen("config", "r");

char line[100];
int linenum = 0;
//int foo;  Uncomment and it starts to working, doesn't matter if you rename it.

while(fgets(line, sizeof(line), file) != NULL) {
    char option[4];
    char arg[100];

    if (line[linenum] == '#') 
        continue;
    linenum++;

    if (sscanf(line, "%s %s", option, arg) != 2)
        fprintf(stderr, "Syntax error, line %i\n", linenum);

Файл конфигурации выглядит следующим образом:

#config file
option1
option2
option3

Итак, результат:

Syntax error, line 1
Syntax error, line 0
Syntax error, line 0

Но если я объявлю переменную int с любым именем доцикл while начинает работать!

Результат:

Syntax error, line 1
Syntax error, line 2
Syntax error, line 3

Что здесь происходит в мире?мой разум взорвется, может быть, это что-то глупое, но я не вижу причин для этого.

Ответы [ 4 ]

3 голосов
/ 22 февраля 2012

Ваш массив option слишком мал (char option[4]), поэтому sscanf перезаписывает другие данные. Неопределенное поведение.

Обычно, когда странные вещи случаются без причины (например, что "работает", пока вы не объявите несвязанную переменную), это происходит из-за проблемы с памятью. Так как вы упомянули gcc, возможно, вы захотите взглянуть на valgrind.

1 голос
/ 22 февраля 2012

Похоже, эта часть как минимум:

if (line[linenum] == '#') continue;
  linenum++;

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

0 голосов
/ 22 февраля 2012

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

  1. Код, который работает или перестает работать, если вы добавляете или удаляете неиспользуемые переменные.
  2. Переменные, которые изменяются без видимой причины.
  3. Код, который иногдаработает нормально и дает сбой в другой раз, используя один и тот же вход.
  4. Код, который дает разные результаты между вызовами, используя один и тот же вход.

В этом случае, как указывают другие ответы, у вас есть две возможные ошибки, связанные с памятью:

Строка if (line[linenum] == '#') continue;

должна быть if (line[0] == '#') continue;

В противном случае индекс будет недействительным, если linenum > 99.

И строка if (sscanf(line, "%s %s", option, arg) != 2){

будет переполнять переменные option и arg, если входные строки слишком длинные.(Ошибка, которую вы видите, происходит потому, что текст ( например option1) длиннее 4 символов и переполняется option. Это можно исправить несколькими способами:

  • Увеличьте размер option. Вам нужно будет знать максимальную длину входных строк, чтобы выбрать подходящий размер.
  • Ограничить количество символов, которые копируются в option:
    if (sscanf(line, "%3s %99s", option, arg) != 2){
    Это может привести к неожиданному выводу для длинных строк ввода, поскольку arg будет содержать остаток строки в option, если она будет усечена.
  • Согласно http://linux.die.net/man/3/sscanf вы можете использовать модификатор a, чтобы указать sscanf выделить память для строк при их чтении:
    char **str1, **str2;
    if (sscanf(line, "%as %as", &str1, &str2) != 2){
0 голосов
/ 22 февраля 2012
if (sscanf(line, "%s %s", option, arg) != 2)

Это переполняет массив option и перезаписывает linenum объект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...