求C语言高手:求解一个困扰我很久却没得解决掉问题? 链表,字符串输入时scanf 和 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: ");
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;
}

温馨提示:答案为网友推荐,仅供参考
相似回答