2014-12-10 3 views
0

, пожалуйста, не могли бы вы мне помочь, как читать строки из stdin через fgets? Проблема заключается в том, что иногда в tmp_string сохраняются часть данных из двух строк до и т.д ... Я использую этот код для загрузки линии:C fgets read lines

int loadLine(Line *line) { 
    char tmp_string[MAX_LOAD]; 
    int return_val; 
    return_val = 0; 
    line->length = MAX_LOAD; 
    line->index = 0; 
    line->data = (char*) malloc(sizeof (char) * line->length); 

    while (fgets(tmp_string, MAX_LOAD - 1, stdin) != NULL) { 
     strncat(line->data, tmp_string, MAX_LOAD); 
     line->index += strlen(tmp_string); 
     if (tmp_string[strlen(tmp_string) - 1] == '\n') { /* if I'm at the end of line... */ 
      line->data[strlen(line->data) - 1] = '\0'; 
      return_val = 1; 
      break; 
     } 
     if ((line->index + MAX_LOAD) > line->length) { 
      resizeLine(line); 
     } 

    } 

    if(feof(stdin)) 
    { 
     return_val = 0; 
    } 

    return return_val; 
} 

А вот использование:

Line line; 
if(loadLine(&line) == 0){ ... } 
free(line.data); 

ответ

1

line->data не был инициализирован (без терминатора), поэтому strncat() может выйти из строя.

line->data = malloc(sizeof (char) * line->length); 
line->data[0] = 0; 
+0

Я думаю, вероятно нет. Обратите внимание, что после 'strncat()', появляется код, который должен гарантировать, что в 'line-> data' имеется как минимум' MAX_LOAD' байт. –

+0

Обратите внимание на проверку длины и вызов 'resizeLine()'. Это может, конечно, выделить больше пространства для 'line-> data' или выделить отдельный, более крупный блок, скопировать содержимое' line-> data' и присвоить его 'line-> data'. Например, через 'realloc()'. –

+0

Недостаток терминатора в 'line-> data' является хорошим уловом, хотя и вероятной причиной проблемы. –

0

Отвечая на вопрос, поставленный вами, ваше использование fgets() выглядит разумным, если вы тратите один байт вашей tmp_string переменной. fgets() функция уже знает, чтобы зарезервировать один байт для завершающего NUL, так что если вы читаете в массив длины MAX_LOAD, то вы обычно используете

fgets(tmp_string, MAX_LOAD, stdin); 

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

Повреждение, которое вы видите, очень вероятно вызвано неспособностью инициализировать line->data до строки нулевой длины, прежде чем передавать ее на strncat(), как и наблюдалось в первую очередь Weather Vane.