【问题标题】:How to use gets and puts with linked list using pointers如何使用指针的链表获取和放置
【发布时间】:2020-03-10 10:42:04
【问题描述】:

我编写了一个链表程序,想用空格输入,但它不起作用。当我简单地将“scanf”与 %s 一起使用时它工作正常,但由于我想用多个空格输入,所以我尝试使用“ gets" 和 "puts" 我也尝试过使用 scanf("%[^\n]*c");但在控制台上它给了我随机垃圾值 scanf("%[^\n]*c");对于“获取”,它读取空白, 现在让我告诉你们一些有关代码及其工作原理的信息 createNode(); 函数基本上只是创建一个新节点来存储在列表中,并将这个新创建的节点的地址返回给insertend(); 函数,它在列表末尾和start=t=newnode 中对齐新节点@start是指向第一个节点的头指针,t 用于遍历列表,直到 t 的值变为 NULL,正如您在 insertend(); 函数的 else 部分中看到的那样,我们正在使用另一个指针 @ 987654332@ 并将 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;
}

【问题讨论】:

  • 请提供minimal verifiable example。例如,我们不知道struct NodecreateNode 的定义。任何一个都可能有(也可能没有)错误。
  • 阅读gets标签的描述并注意警告。
  • 提供完整代码!
  • C 语言中不再有函数gets。您需要用过去 20 年更新的学习资源替换当前的学习资源。
  • 欢迎来到 Stack Overflow!请edit您的代码将其减少为您的问题的minimal reproducible example。您当前的代码包含许多与您的问题无关的内容 - 因为您询问的是 scanf(),所以您无需使用任何链表代码来给我们带来负担。

标签: c data-structures linked-list gets puts


【解决方案1】:

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()(Linux 系统中的 ncurses.h)也是如此,所以我对此示例进行了评论。

Live sample here

#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")] = '\0'; //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;
}

【讨论】:

  • "如果你使用 [^\n] 它应该可以工作" --> scanf("%[^\n]*c") 也有很多问题,包括没有宽度限制,gets() 的关键问题。
  • @anastaciu 我尝试使用 fgets(newnode->first, sizeof(newnode->first), stdin) 但仍然需要空白输入。我还添加了结构代码,请查看问题当前已关闭我已对其进行编辑并要求重新打开它,一旦打开,请提供答案!提前致谢
  • @ansme,关于你贴的代码还有很多问题,比如createNode();做什么,start=t=newnode;应该做什么,所有这些变量的声明在哪里,这就是为什么发布一段可重现的代码很重要的原因,有人可以将这段代码复制到编译器并重现所描述的问题。
  • @anastaciu 您好,我已经更新了问题并添加了代码,只需复制和粘贴即可编译。我还在每个函数前面添加了 cmets 来解释它们的作用,但 createNode(); 函数基本上只是创建一个新节点来存储在列表中,并将这个新创建的节点的地址返回给 insertend(); 函数它在列表末尾对齐新节点,start=t=newnode start 是指向第一个节点的头指针,t 用于遍历列表,直到 t 的值变为 NULL。
  • @anastaciu 非常感谢您花时间详细解释并解决我的问题,我理解您所解释的一切,而且我已经学会了如何清理缓冲区不使用 fflush(stdin)。我对社区有点陌生,经验不多,但因为像你这样的人,我仍然感觉很棒!所以我要再次感谢你,祝你有美好的一天! :)
猜你喜欢
  • 2018-11-30
  • 1970-01-01
  • 2018-09-29
  • 1970-01-01
  • 2014-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多