如何使用指针对链表使用 gets 和 puts
How to use gets and puts with linked list using pointers
我写了一个链表程序,想用 spaces 获取输入,但它不是 working.It 当我简单地使用 "scanf" 和 %s 时它工作正常但是因为我想使用多个 spaces 输入我尝试使用 "gets" 和 "puts" 我也尝试过使用 scanf("%[^\n]*c");但在控制台上它给了我 scanf("%[^\n]*c"); 的随机垃圾值对于 "gets",它显示为空白 space,
现在让我告诉你们一些关于代码及其工作原理的信息
createNode();
函数基本上只是创建一个新节点存储在列表中,returns 这个新创建节点的地址到 insertend();
函数,它将新节点对齐到列表的末尾在start=t=newnode
中,start
是指向第一个节点的头指针,t
用于遍历列表,直到t的值变为NULL,正如您在[=16中看到的那样=] 部分 insertend();
函数我们使用另一个指针 t
并将 start 的值存储在其中,以便我们可以遍历列表而不会丢失最初保留的第一个节点的地址在 start
指针中。
这是代码 ->
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
struct Node
{
char first[20];
struct Node* next;
};
struct Node* start=NULL;
struct Node* t,*u;
int i=1;
struct Node* createNode() //this function creates a newnode everytime it's called
{
struct Node* create=(struct Node*)malloc(sizeof(struct Node));
return create;
}
int length() //to measure the length of the list.
{
int count = 0;
struct Node* temp;
temp=start;
while(temp!=NULL)
{
count++;
temp = temp->next;
}
return count;
}
void insertend() //to insert a node at the end of the list.
{
int l;
struct Node* newnode = createNode();
printf("Enter Name : ");
fgets(newnode->first,sizeof(newnode->first),stdin);
if(start==NULL)
{
start=t=newnode;
start->next=NULL;
}
else
{
t=start;
while(t->next!=NULL)
t=t->next;
t->next=newnode;
t=newnode;
t->next=NULL;
printf("%s successfully added to the list!",newnode->first);
}
l=length();
printf("The length of the list is %d",l);
}
void display() //to display the list
{
struct Node* dis;
dis=start;
if(start==NULL)
{
system("cls");
printf("No elements to display in the list");
}
else
{
system("cls");
for(int j=1;dis!=NULL;j++)
{
printf("%d.) %s\n",j,dis->first);
dis=dis->next;
}
}
}
int menu() //this is just a menu it returns the user input to the main function
{
int men;
printf("Please select a choice from the options below :-\n\n");
printf("1.) Add at the end of the list\n");
printf("2.) Display list\n");
printf("3.) exit\n");
printf(" Enter your choice : ");
scanf("%d",&men);
return men;
}
int main()
{
while(1)
{
system("cls");
switch(menu())
{
case 1 : insertend();
break;
case 2 : display();
break;
case 3: exit(0);
default : system("cls"); printf("Ivalid choice!Please select an appropriate option!");
fflush(stdin);
break;
}
getch();
}
return 0;
}
gets
不被使用,由于缺乏安全性,它已从 C 标准中删除。
如果您想了解更多信息,请阅读 Why is the gets function so dangerous that it should not be used?
如果你使用 [^\n]
它应该可以工作,尽管它也有问题,因为这个说明符不限制只读流的长度,它必须在找到换行符时停止。
我怀疑问题可能出在容器而不是读取,可能是未初始化的内存,如果您提供结构代码将更容易诊断。
你可以试试:
fgets(newnode->first, sizeof(newnode->first), stdin)
有一个警告:
- 如果输入流大于容器,多余的字符将保留在输入缓冲区中,您可能需要丢弃它们。
编辑:
所以主要的问题是,通过你的代码,你在缓冲区中有挥之不去的字符,在你的 fgets
输入的特定情况下,它会捕获缓冲区中留下的 '\n'
,所以它会在输入流之前读取它,再次将它留在缓冲区中。
我添加了一个清理缓冲区的功能,请注意 fflush(stdin) leads to undefined behaviour 所以这是一个错误的选择。
我还添加了一些小调整。
- 请注意 conio.h
是 windows 特定的 system("cls")
和 getch()
(ncurses.h 在 Linux系统)所以我为这个示例评论了它。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
struct Node
{
char first[20];
struct Node *next;
};
struct Node *start = NULL;
struct Node *t, *u;
void clear_buf(){ //clear stdin buffer
int c;
while((c = fgetc(stdin)) != '\n' && c != EOF){}
}
struct Node *createNode() //this function creates a newnode everytime it's called
{
struct Node *create = malloc(sizeof(struct Node));
return create;
}
int length() //to measure the length of the list.
{
int count = 0;
struct Node *temp;
temp = start;
while (temp != NULL)
{
count++;
temp = temp->next;
}
return count;
}
void insertend() //to insert a node at the end of the list.
{
int l;
struct Node *newnode = createNode();
printf("Enter Name : ");
clear_buf(); //clear buffer before input
fgets(newnode->first, sizeof(newnode->first), stdin);
newnode->first[strcspn(newnode->first, "\n")] = '[=11=]'; //remove '\n' from char array
if (start == NULL)
{
start = t = newnode;
start->next = NULL;
printf("%s successfully added to the list!", newnode->first);
}
else
{
t = start;
while (t->next != NULL)
t = t->next;
t->next = newnode;
t = newnode;
t->next = NULL;
printf("%s successfully added to the list!", newnode->first);
}
l = length();
printf("The length of the list is %d", l);
}
void display() //to display the list
{
const struct Node *dis;
dis = start;
if (start == NULL)
{
system("cls");
printf("No elements to display in the list");
}
else
{
system("cls");
for (int j = 1; dis != NULL; j++)
{
printf("%d.) %s\n", j, dis->first);
dis = dis->next;
}
}
}
int menu() //this is just a menu it returns the user input to the main function
{
int men;
printf("\nPlease select a choice from the options below :-\n\n");
printf("1.) Add at the end of the list\n");
printf("2.) Display list\n");
printf("3.) exit\n");
printf(" Enter your choice : ");
scanf("%d", &men);
return men;
}
int main()
{
while (1)
{
system("cls");
switch (menu())
{
case 1:
insertend();
break;
case 2:
display();
break;
case 3:
exit(0);
default:
system("cls");
printf("Ivalid choice!Please select an appropriate option!");
clear_buf();
break;
}
getch();
}
return 0;
}
我写了一个链表程序,想用 spaces 获取输入,但它不是 working.It 当我简单地使用 "scanf" 和 %s 时它工作正常但是因为我想使用多个 spaces 输入我尝试使用 "gets" 和 "puts" 我也尝试过使用 scanf("%[^\n]*c");但在控制台上它给了我 scanf("%[^\n]*c"); 的随机垃圾值对于 "gets",它显示为空白 space,
现在让我告诉你们一些关于代码及其工作原理的信息
createNode();
函数基本上只是创建一个新节点存储在列表中,returns 这个新创建节点的地址到 insertend();
函数,它将新节点对齐到列表的末尾在start=t=newnode
中,start
是指向第一个节点的头指针,t
用于遍历列表,直到t的值变为NULL,正如您在[=16中看到的那样=] 部分 insertend();
函数我们使用另一个指针 t
并将 start 的值存储在其中,以便我们可以遍历列表而不会丢失最初保留的第一个节点的地址在 start
指针中。
这是代码 ->
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
struct Node
{
char first[20];
struct Node* next;
};
struct Node* start=NULL;
struct Node* t,*u;
int i=1;
struct Node* createNode() //this function creates a newnode everytime it's called
{
struct Node* create=(struct Node*)malloc(sizeof(struct Node));
return create;
}
int length() //to measure the length of the list.
{
int count = 0;
struct Node* temp;
temp=start;
while(temp!=NULL)
{
count++;
temp = temp->next;
}
return count;
}
void insertend() //to insert a node at the end of the list.
{
int l;
struct Node* newnode = createNode();
printf("Enter Name : ");
fgets(newnode->first,sizeof(newnode->first),stdin);
if(start==NULL)
{
start=t=newnode;
start->next=NULL;
}
else
{
t=start;
while(t->next!=NULL)
t=t->next;
t->next=newnode;
t=newnode;
t->next=NULL;
printf("%s successfully added to the list!",newnode->first);
}
l=length();
printf("The length of the list is %d",l);
}
void display() //to display the list
{
struct Node* dis;
dis=start;
if(start==NULL)
{
system("cls");
printf("No elements to display in the list");
}
else
{
system("cls");
for(int j=1;dis!=NULL;j++)
{
printf("%d.) %s\n",j,dis->first);
dis=dis->next;
}
}
}
int menu() //this is just a menu it returns the user input to the main function
{
int men;
printf("Please select a choice from the options below :-\n\n");
printf("1.) Add at the end of the list\n");
printf("2.) Display list\n");
printf("3.) exit\n");
printf(" Enter your choice : ");
scanf("%d",&men);
return men;
}
int main()
{
while(1)
{
system("cls");
switch(menu())
{
case 1 : insertend();
break;
case 2 : display();
break;
case 3: exit(0);
default : system("cls"); printf("Ivalid choice!Please select an appropriate option!");
fflush(stdin);
break;
}
getch();
}
return 0;
}
gets
不被使用,由于缺乏安全性,它已从 C 标准中删除。
如果您想了解更多信息,请阅读 Why is the gets function so dangerous that it should not be used?
如果你使用 [^\n]
它应该可以工作,尽管它也有问题,因为这个说明符不限制只读流的长度,它必须在找到换行符时停止。
我怀疑问题可能出在容器而不是读取,可能是未初始化的内存,如果您提供结构代码将更容易诊断。
你可以试试:
fgets(newnode->first, sizeof(newnode->first), stdin)
有一个警告:
- 如果输入流大于容器,多余的字符将保留在输入缓冲区中,您可能需要丢弃它们。
编辑:
所以主要的问题是,通过你的代码,你在缓冲区中有挥之不去的字符,在你的 fgets
输入的特定情况下,它会捕获缓冲区中留下的 '\n'
,所以它会在输入流之前读取它,再次将它留在缓冲区中。
我添加了一个清理缓冲区的功能,请注意 fflush(stdin) leads to undefined behaviour 所以这是一个错误的选择。
我还添加了一些小调整。
- 请注意 conio.h
是 windows 特定的 system("cls")
和 getch()
(ncurses.h 在 Linux系统)所以我为这个示例评论了它。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
struct Node
{
char first[20];
struct Node *next;
};
struct Node *start = NULL;
struct Node *t, *u;
void clear_buf(){ //clear stdin buffer
int c;
while((c = fgetc(stdin)) != '\n' && c != EOF){}
}
struct Node *createNode() //this function creates a newnode everytime it's called
{
struct Node *create = malloc(sizeof(struct Node));
return create;
}
int length() //to measure the length of the list.
{
int count = 0;
struct Node *temp;
temp = start;
while (temp != NULL)
{
count++;
temp = temp->next;
}
return count;
}
void insertend() //to insert a node at the end of the list.
{
int l;
struct Node *newnode = createNode();
printf("Enter Name : ");
clear_buf(); //clear buffer before input
fgets(newnode->first, sizeof(newnode->first), stdin);
newnode->first[strcspn(newnode->first, "\n")] = '[=11=]'; //remove '\n' from char array
if (start == NULL)
{
start = t = newnode;
start->next = NULL;
printf("%s successfully added to the list!", newnode->first);
}
else
{
t = start;
while (t->next != NULL)
t = t->next;
t->next = newnode;
t = newnode;
t->next = NULL;
printf("%s successfully added to the list!", newnode->first);
}
l = length();
printf("The length of the list is %d", l);
}
void display() //to display the list
{
const struct Node *dis;
dis = start;
if (start == NULL)
{
system("cls");
printf("No elements to display in the list");
}
else
{
system("cls");
for (int j = 1; dis != NULL; j++)
{
printf("%d.) %s\n", j, dis->first);
dis = dis->next;
}
}
}
int menu() //this is just a menu it returns the user input to the main function
{
int men;
printf("\nPlease select a choice from the options below :-\n\n");
printf("1.) Add at the end of the list\n");
printf("2.) Display list\n");
printf("3.) exit\n");
printf(" Enter your choice : ");
scanf("%d", &men);
return men;
}
int main()
{
while (1)
{
system("cls");
switch (menu())
{
case 1:
insertend();
break;
case 2:
display();
break;
case 3:
exit(0);
default:
system("cls");
printf("Ivalid choice!Please select an appropriate option!");
clear_buf();
break;
}
getch();
}
return 0;
}