结构中的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;
}