Помогите с пользовательской функцией getline () - PullRequest
2 голосов
/ 30 января 2009

Может кто-нибудь объяснить мне, почему это не работает?

#include <stdio.h>
#include <stdlib.h>

char *getline(int lim)
{
    char c;
    int i;
    char *line;
    line = malloc(sizeof(char) * lim);


    i = 0;
    while((c = getchar()) != '\n' && c != EOF && i < lim-1)
    {
        *line = c;
        line++;
        i++;
    }
    *line = '\0';
    printf("%s", line);
    return line;
}

Меня сейчас не беспокоит возвращаемое значение - только причина того, почему printf("%s", line) не работает.

Спасибо!

РЕДАКТИРОВАТЬ: исправлено на line = malloc(sizeof(char) * lim);, но оно все еще не работает.

Решение: адрес *line увеличивался по всей функции. Когда он был передан в printf(), *line указывал на '\ 0', потому что там его адрес был увеличен. Использование временного указателя, в котором сохранен исходный адрес, выделенный от malloc() до *line, а затем передача этого указателя в printf(), позволило функции пройти по указателю.

Ответы [ 8 ]

5 голосов
/ 30 января 2009

Поскольку вы выделяете достаточно места только для одного символа в этой строке:

line = malloc(sizeof(char));

И это заполняется \0 до вашего printf заявления.

Полагаю, вы хотите изменить эту строку на:

/* Allocate enough room for 'lim' - 1 characters and a trailing \0 */
line = malloc(sizeof(char) * lim);

Или даже лучше:

char *line, *tmp;
tmp = line = malloc(sizeof(char) * lim);

А затем используйте tmp во всей вашей математике указателя, таким образом line все равно будет указывать на начало вашей строки.

И я знаю, что это в начале вашей разработки, но вы захотите убедиться, что вы free() память, которую вы malloc().


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

#include <stdio.h>
#include <stdlib.h>

char *getline(int lim)
{
    char c;
    int i;
    char *line, *tmp;
    tmp = line = malloc(sizeof(char) * lim);

    i = 0;
    /* NOTE: 'i' is completely redundant as you can use 'tmp',
     * 'line,' and 'lim' to determine if you are going to
     * overflow your buffer */
    while((c = getchar()) != '\n' && c != EOF && i < lim-1)
    {
        *tmp = c;
        tmp++;
        i++;
    }
    *tmp = '\0';
    printf("%s", line);
    return line;
}
3 голосов
/ 30 января 2009

Похоже, вы печатаете строку нулевой длины.

*line = '\0';
printf("%s", line);

Я предполагаю, что вы хотите сохранить исходное значение line (как возвращено из malloc) и распечатать его.

1 голос
/ 30 января 2009

Все уже рассмотрели эти пункты, но вот все это вместе:

Редактировать: Немного улучшен код

#include <stdio.h>
#include <stdlib.h>

char *getline(int lim)
{
    char *result = malloc(sizeof(char) * lim); // allocate result buffer

    int i = 0;
    char c;
    char *line = result;
    while((c = getchar()) != '\n' && c != EOF && i < lim-1)
    {
        *line = c;
        line++;
        i++;
    }
    *line = '\0';

    printf("%s", result); // print the result
    return result; // return the result buffer (remember to free() it later)
}
1 голос
/ 30 января 2009

Обновлено - это была простая опечатка, но вы не должны были голосовать за нее

вместо

     char *line= malloc(sizeof(char));

попробуй

    int space= //number of how many characters you need on the line
    char *line= malloc(sizeof(char)*space);

извините, я имел в виду

   char *line= malloc( sizeof(char)*lim)
1 голос
/ 30 января 2009

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

line = malloc(lim * sizeof(char));

Кроме того, вы не хотите изменять line после прочтения каждого символа. Вместо этого используйте следующий блок для цикла while:

*(line + i) = c;
i++;

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

*(line + i) = '\0';
0 голосов
/ 30 января 2009

Вы делаете ошибку по двум пунктам (но вы можете сказать ту же ошибку или две, это до вас). сначала ваш указатель должен быть увеличен как

* (строка + i) = с; По этой причине, когда вы устанавливаете нулевой символ в конце цикла, вы на самом деле говорите компилятору, чтобы он указывал только на эту позицию. Но указатель указывает только на пустую строку, а не на всю строку. Так как он постоянно перемещался на каждом этапе цикла. Поэтому, когда вы пытались напечатать, указателю нечего печатать. Поэтому, если вы измените свой оператор в цикле для указателя и назначите значение для экспресс-адреса, а не просто передвинете указатель, тогда ваша проблема будет решена.

Примечание. Если вы измените эту строку, то вам также нужно будет изменить свое назначение терминатора Null следующим образом; * (строка + предел) = '\ 0';

0 голосов
/ 30 января 2009

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

0 голосов
/ 30 января 2009

Вы также перезаписываете память, которой не владеете. Вы неправильно используете один символ, устанавливаете * line на c, а затем увеличиваете строку и повторяете.

...