scanf char * word в структуре показывает только последний ввод - PullRequest
0 голосов
/ 19 декабря 2011

Мне разрешено использовать только следующие заголовки

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

и я определил свой struct student следующим образом:

struct dict
{
    char* word;
    struct dict* link;
};

Есть много функций, но только одна функция, с которой у меня сейчас проблемы. Эта функция вставляет в конец ссылки struct dict с определенным именем.

struct student *Linsert(struct dict *list, char *name)
{
    struct student *pnew;
    struct student *pn;
    int exist = 1;

    pnew = (struct dict *)malloc(sizeof(struct dict));
    pnew -> next = NULL;
    pnew -> name = name;

    if (list != NULL)
    {
        for (pn = list; pn -> next != NULL; pn = pn -> next) ;
        pn -> next = pnew;
    }
    else
        list = pnew;

    return list;
}

Используя следующую функцию,

//print all the values in the list
void printList(struct dict* list);

Я сделал это:

int main(void)
{

    struct dict *list = NULL;

    char *name;

    while (1) {
        scanf("%s", name);
        if (name == 'Q')
            break;

        list = Linsert(list, name);
        printList(list);
    }
    return 0;
}

Допустим, для ввода я набрал три apple banana и orange, мой результат показывает три моих последних ввода.

В чем здесь проблема?

Ответы [ 5 ]

3 голосов
/ 19 декабря 2011

Я вижу две проблемы с вашим кодом:

  • Вам необходимо передать scanf массив char размера, достаточный для хранения входной строки, а не просто указатель на символ.
  • Вам необходимо скопировать строки, переданные в Linsert (используйте strdup).
2 голосов
/ 19 декабря 2011

У вашего main фрагмента есть целый ряд проблем:

  • name - неинициализированный указатель;он указывает на какое-то неизвестное место в памяти, которое вы не распределили и не можете использовать, что вызывает неопределенное поведение.Возможно, вы хотите, чтобы char name[20] выделил в стеке массив из 20 char с, а scanf сохранил входные данные в этом буфере.1014 * (указатель на начало строки) с одним char 'Q' - вы сравниваете указатель и целочисленное значение, как вам скажут предупреждения вашего компилятора.Вы не сравниваете содержимое строки для значения 'Q', вы сравниваете адрес памяти name и целочисленное значение для 'Q'.Если вы хотите сравнить строку name со строкой "Q", используйте strcmp и проверьте возвращаемое значение 0.

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

Если вы включите предупреждения компилятора, вы получите еще больше предупреждений.

1 голос
/ 19 декабря 2011

Одна из проблем заключается в том, что вы не выделили хранилище для элемента word, на который можно указать. Вы также не выделили место для name, на которое можно указать. Это основная причина проблем.

Вам необходимо выделить место для name; самый простой способ:

char name[128];

Вам необходимо выделить место для хранения слова, и вам необходимо скопировать содержимое name в word, чтобы при перезаписи следующей строки name он не уничтожал сохраненные word.

Адаптируя свой код, вы можете использовать:

struct student *Linsert(struct dict *list, char *name)
{
    struct student *pnew;
    struct student *pn;

    pnew = (struct dict *)malloc(sizeof(struct dict));
    if (pnew == 0)
        ...error...
    pnew->next = NULL;
    pnew->word = malloc(strlen(name) + 1);
    if (pnew->word == 0)
        ...error...
    strcpy(pnew->word, name);

    if (list != NULL)
    {
        for (pn = list; pn->next != NULL; pn = pn->next)
            ;
        pn->next = pnew;
    }
    else
        list = pnew;

    return list;
}

Не пропускайте проверки ошибок при распределении памяти - хотя это и болезненно. Он будет кусать тебя, когда ты забудешь.

Стилистически, не используйте пробелы вокруг -> или .; это операторы, которые очень тесно связаны, и их не следует разносить, как другие бинарные операторы.

Есть удобная функция, strdup(), дублирует строку, но это не стандартный C (это стандартный POSIX).

1 голос
/ 19 декабря 2011

Вы не выделяете память для имени, поэтому scanf записывает в какое-то случайное место и перезаписывает это каждый раз в цикле.

0 голосов
/ 19 декабря 2011

Поскольку name является указателем на символ, ваше присвоение полю каждой структуры dict будет использовать последнее значение, на которое он указывает.

...