Ошибка в моей собственной версии getline - PullRequest
0 голосов
/ 16 января 2012

Я пытаюсь сделать простую версию getline.Он должен прочитать строку из stdin, перераспределяя размер буфера по мере необходимости.Также должно возвращаться количество прочитанных символов.Требуется символ **, чтобы перераспределенный буфер мог быть позже освобожден.Почему я получаю 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);

Ответы [ 3 ]

6 голосов
/ 16 января 2012

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

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

И

(*buff)[length] = c;

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

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

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

5 голосов
/ 16 января 2012

Вы не определяете 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». Я подозреваю, что таких тоже может быть несколько.

4 голосов
/ 16 января 2012

Линия

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

должно быть

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

Также

buf[length] = c

должно быть

*buf[length] = c

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

...