Ошибка Seg в моей собственной версии getline

Я пытаюсь сделать простую версию getline. Он должен считывать строку со стандартного ввода, перераспределяя размер буфера по мере необходимости. Он также должен возвращать количество прочитанных символов. Он принимает char **, чтобы перераспределенный буфер можно было позже освободить. Почему я получаю segfault?

Вот моя версия:

int get_input_line(char **buff, int start_size) {
char c;
int stop = 0, length = 0, k = start_size;
while(!stop) {
    if(length > k) {
        k += 50;
        buff = (char *)(realloc(buff, start_size + 1));
    }
    c = getchar();
    if(c == '\n'){
        stop = 1;
    }
    buff[length] = c; 
    length++;
}
return length;
}

И вот звонок:

char *buff = (char *)(malloc(50 + 1));
get_input_line(&buff, 50);
printf("%s", buff);

person MEURSAULT    schedule 15.01.2012    source источник
comment
Это не отвечает на вопрос, но вы также не проверяете возвращаемое значение ни malloc, ни realloc. Если любой из них вернет NULL, вы, вполне возможно, получите сбой во время выполнения для ссылки на null.   -  person Nick Shaw    schedule 16.01.2012


Ответы (3)


Вы не обнаруживаете EOF надежно. Вам нужно сохранить результат getchar() в int, а не char. И вы не должны пытаться хранить EOF в своем буфере.

Вы не проверяете распределение памяти.

Вы не нуль, завершающий выходную строку, поэтому printf() в main() может привести к сбою.

Вы кого-то сбиваете с толку (может быть, меня, может быть, компилятора, может быть, самого себя), выделяя 51 байт и говоря функции, что у нее есть только 50 байтов для игры.

И, в частности, вы должны использовать *buff в большинстве точек внутри функции, в том числе, в частности, при добавлении символа:

(*buff)[length++] = c;

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

Кроме того, вы неправильно называете realloc() по трем причинам. Одним из них является проблема *buff. Во-вторых, вы хотите, чтобы размер был k, а не start_size + 1. Во-вторых, вы присваиваете результат входному параметру. Это «нет-нет», потому что, если выделение не удается, вы теряете указатель на ранее (и все еще) выделенные данные. Всегда используйте идиому:

void *new_data = realloc(old_data, new_size);
if (new_data == 0)
    ...deal with out of memory error...
else
{
    old_data = new_data;
    old_size = new_size;
}

Применительно к вашему коду это означает:

char *new_buff = (char *)realloc(*buff, k); // NOT start_size+1!!!
if (new_buff == 0)
    ...deal with out of memory error...
else
    *buff = new_buff;

Есть те, кто возражает против броска на malloc() и realloc() и calloc(); есть те, кто предпочитает присутствующие слепки. С обеих сторон есть аргументы разной степени обоснованности. Я предпочитаю актерский состав - я уважаю тех, кто предпочитает без актерского состава. Мы приходим к разным выводам по разным причинам.

Я не изучал код для других ошибок 'off-by-one'. Подозреваю, что их тоже может быть несколько.

person Jonathan Leffler    schedule 15.01.2012
comment
почему вы предпочитаете литье? кроме совместимости с C++, я не вижу никакой веской причины. - person ouah; 16.01.2012
comment
Я считаю, что мой код C компилируется компилятором C++, так что это именно для совместимости с C++. Это мое добровольное требование; если у вас нет этого требования, не включайте актерский состав. - person Jonathan Leffler; 16.01.2012

Вы, вероятно, имели в виду:

*buff = (realloc(*buff, new_size));
^                ^

А также

(*buff)[length] = c;

Вам также не хватает терминатора 0.

РЕДАКТИРОВАТЬ

Как указывает nos, length > k должно быть length >= k .

person cnicutar    schedule 15.01.2012
comment
И length > k должно быть length >= k - person nos; 16.01.2012
comment
И выделенный размер должен быть k или k+1, а не start_size+1. - person Jonathan Leffler; 16.01.2012
comment
@JonathanLeffler Да, список проблем можно продолжать и продолжать (char getchar и т. д.). Ваш пост лучше перечисляет все проблемы :-) - person cnicutar; 16.01.2012
comment
@cnicutar Не могли бы вы обновить свой ответ (достаточно даже пробела)? Я проверял ТАК со своего айпада, и каким-то образом он проголосовал за ваш хороший ответ. Кажется, я не могу отменить свой голос против, так как он теперь заблокирован и хочет, чтобы ответ был обновлен. Приносим искренние извинения за неудобства. - person jaypal singh; 16.01.2012

Линия

buff = (char *)(realloc(buff, start_size + 1));

должно быть

*buff = (char *)(realloc(*buff, k + 1));

Также

buf[length] = c

должно быть

*buf[length] = c

Более того, я думаю, вы забыли сохранить конечный '\0'.

person celtschk    schedule 15.01.2012