求C语言高手:求解一个困扰我很久却没得解决掉问题? 链表,字符串输入时scanf 和 gets 之间的问题?
# include "malloc.h"
# include "string.h"
struct node
{
char name[20];
char tel[20];
struct node * next;
};
typedef struct node AA;
# define NEW (AA *)malloc(sizeof (AA))
AA *greatline(void);
void printline(AA *);
void newline(AA *, char *, char *, char *);
void deleteline(AA *, char *);
int main(void)
{
AA *head;
char name[20];
char newname[20], newtel[20];
head = greatline();
printline(head);
printf("before name: ");
gets(name);
printf("Add newname and newtel: ");
scanf("%s%s", newname, newtel);
newline(head, name, newname, newtel);
printline(head);
printf("input delete name: ");
scanf("%s", name); //******为什么这里用gets(name);运 行的时候就会报错???
//******用scanf(),就能通过,看下面截图。
deleteline(head, name);
printline(head);
return 0;
}
AA *greatline(void) //建立一个链表
{
AA *h = NEW;
AA *q = h;
AA *p = NULL;
char name[20];
printf("name: ");
gets(name);
while (strlen(name) != 0)
{
p = NEW;
strcpy(p->name, name);
printf("tel: ");
gets(p->tel);
p->next = NULL;
q->next = p;
q = p;
printf("name: ");
gets(name);
}
return h;
}
void printline(AA *head) //输出链表
{
AA *p = head->next;
while (p != NULL)
{
printf("%s %s\n", p->name, p->tel);
p = p->next;
}
}
void newline(AA *head, char *name, char *newname, char *newtel) //在链表中加入一个新元素
{
AA *s = NEW;
AA *q = head;
AA *p = head->next;
strcpy(s->name, newname);
strcpy(s->tel, newtel);
while (strcmp(p->name, name) != 0)
{
q = p;
p = p->next;
}
q->next = s;
s->next = p;
}
void deleteline(AA *head, char *name) //删除链表中一个元素
{
AA *q = head;
AA *p = head->next;
while(strcmp(p->name, name) != 0)
{
q = p;
p = p->next;
}
q->next = p->next;
}
小弟百思不得其解, 我用了gets(name)之后,就如图,用scanf("%s", name) 就没有问题?谁帮帮我分析分析,跪谢!!!! 展开
原因是scanf和gets处理方式不同:前者是按字符读并依次处理后放入对应的变量中,通常遇到换行符'0x0A'才结束,单不读入这个换行符,所以这个换行符还在缓冲区中,而后者读入时遇到换行符中止,且抛弃换行符。
所以,你那里把scanf换成gets时由于之前(26行)的scanf还留有一个换行符,gets直接读入了这个换行符,但name中实际为空串(长度为零),所以后面你的查询部分没有对长度进行判断,同时你的链表最后一个指针没有初始化(应该设置为NULL,并在遍历时判断这个指针作为是否链表结束的标志),所以导致失败。
目前通过在gets前加一句fflush(stdin)可以清除换缓冲区,但没有试过输入的名字找不到时是否也出同样的错误(粗看你代码觉得应该等价),自己再检查测试一下。
初步验证了,在printf("before name: "); gets(name);处如果输入的name在链表中找不到时也同样报错。所以真正的错误原因是指针检查不严,gets只是触发条件而已。
所以你应该加上必要的容错处理。
下面是我测试的代码,加上了少量的容错后仍然会出错。
# include <stdio.h >
# include <malloc.h>
# include <string.h>
struct node
{
char name[20];
char tel[20];
struct node * next;
};
typedef struct node AA;
# define NEW (AA *)malloc(sizeof (AA))
AA *greatline(void);
void printline(AA *);
void newline(AA *, char *, char *, char *);
void deleteline(AA *, char *);
int main(void)
{
AA *head;
char name[20];
char newname[20], newtel[20];
head = greatline();
printline(head);
printf("before name: ");
gets(name);
printf("Add newname and newtel: ");
scanf("%s%s", newname, newtel);
newline(head, name, newname, newtel);
printline(head);
printf("input delete name: ");
//fflush(stdin);
printf("%2X\n", getchar());//相当于fflush(stdin)
gets(name); //******为什么这里用gets(name);运 行的时候就会报错???
//******用scanf(),就能通过,看下面截图。
if(strlen(name) > 0) //加了容错
{
deleteline(head, name);
printline(head);
}
return 0;
}
有道理,之前,我曾经试过在gets前加个getchar()语句,好像通过运行,不明白为啥!姑且错对不论,经你这么一说,虽没彻底懂,但也明白大概了!非常感谢!
本来贴图了,没上去,不知道为什么。
这是我修改后的main函数,参考一下。
int main(void)
{
AA *head;
char name[20];
char newname[20], newtel[20];
head = greatline();
printline(head);
printf("before name: ");
gets(name);
printf("Add newname and newtel: ");
scanf("%s%s", newname, newtel);
newline(head, name, newname, newtel);
printline(head);
printf("input delete name: ");
//fflush(stdin);
printf("%2X\n", getchar()); //和fflush等价。
gets(name); //******为什么这里用gets(name);运 行的时候就会报错???
//******用scanf(),就能通过,看下面截图。
if(strlen(name) > 0) //这里简单加了一个防错检测。但before name时输入行中没有的name时,即使清除缓冲区也不行,说明还是你的指针检测没有加,导致指针值指向了非法空间。
{
deleteline(head, name);
printline(head);
}
return 0;
}