结构中的scanf char*word仅显示最后一次输入

结构中的scanf char*word仅显示最后一次输入,c,struct,char,scanf,C,Struct,Char,Scanf,我只允许使用以下标题 #include <stdio.h> #include <stdlib.h> 有很多函数,但现在只有一个函数有问题。 此函数用于在链接末尾插入具有特定名称的结构dict struct student *Linsert(struct dict *list, char *name) { struct student *pnew; struct student *pn; int exist = 1; pnew = (s

我只允许使用以下标题

#include <stdio.h>
#include <stdlib.h> 
有很多函数,但现在只有一个函数有问题。 此函数用于在链接末尾插入具有特定名称的结构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;
}
使用以下函数

我这样做:

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
,我的结果显示了我最后输入的三个


这里的问题是什么?

您没有为名称分配任何内存,因此scanf正在写入某个随机位置,并在循环中每次都覆盖该位置。

一个问题是您没有为指向的
word
成员分配存储空间。您还没有为要指向的
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)。

我发现您的代码有两个问题:

  • 您需要传递一个大小足以存储输入字符串的
    scanf
    数组,而不仅仅是一个字符指针
  • 您需要复制传递到
    Linsert
    (使用
    strdup
    )中的字符串

您的
main
代码片段本身就有一大堆问题:

  • name
    是未初始化的指针;它指向内存中的某个未知位置,您尚未分配该位置并允许使用该位置,因此会导致未定义的行为。也许您希望
    char name[20]
    在堆栈上分配一个由20个
    char
    s组成的数组,并让
    scanf
    将输入存储在此缓冲区中

  • 您正在将
    char*
    (指向字符串开头的指针)与单个
    char
    'Q'
    进行比较-正如编译器警告所示,您正在将指针与整数值进行比较。您不是在比较值
    'Q'
    的字符串内容,而是在比较
    name
    的内存地址和
    'Q'
    的整数值。如果要将字符串
    name
    与字符串
    “Q”
    进行比较,请使用
    strcmp
    并检查返回值是否为0

您还需要创建传递给
Linsert
的变量的副本,否则,正如您所注意到的,每次都会传递一个指向内存中相同位置的指针,并且对该内存块的更改将更改您的每个项


如果你打开编译器警告,你会得到更多的警告。

因为
name
是一个字符指针,你对每个
dict
结构的字段的赋值将使用它指向的最新值

始终使用所有警告进行编译,不要忽略任何警告。下次请查看,特别是如何格式化代码块。@KerrekSB
-Wall-Wextra-Werror
总是会产生更好的代码
:)
这是实际的代码吗?您的结构具有
struct dict*链接
,但您的代码使用
->next
。这本不应该被编译。请复制并粘贴代码,不要重新键入…这看起来有点像家庭作业。此外,这是一个很好的调试器(如gdb)和单步调试代码的地方。
char name[128];
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;
}