无法将元素存储在链接列表中

时间:2019-03-28 07:50:21

标签: c list segmentation-fault

我的目标是创建一个链接列表并将元素存储在该列表中。

struct node
{ 
  int a;
  struct  node *b;
} p,*temp,*head;


void create ( struct node *temp)
{
  char c;

  temp = malloc (sizeof(struct node));

  printf("enter data\n");

  scanf(" %d",&temp->a);

  printf("do you want to insert another node y/n\n");

  scanf("%s", &c);
  if (c=='y')
  {
    create(temp->b);
  }
  else if ( c=='n')
  {
     temp->b= NULL;
     temp=&p;
     return;
   }
}

void traverse ( struct node *head)
{
   while(head != NULL)
   {
     printf("%d  ",head->a);
     head=head->b;
   }
}

int main ()
{
   int i,j,k,l,m,n;

   do{
     if(i==1)
     {
       printf("enter data\n");
       scanf("%d",&p.a);

       create (p.b);
     }
     else if ( i==2)
      traverse(temp);
    }
    while(i!=3);

    printf("%d",temp->a);
}

一旦存储了元素,我将无法恢复。当我尝试遍历列表时,它只给我列表的第一个元素,而没有其他内容。

3 个答案:

答案 0 :(得分:3)

主要

 do {
   if(i==1)
   {
   ...
   }
   else if ( i==2)
     traverse(temp);
 }
 while(i!=3);

必须类似

 do {
   if (scanf("%d", &i) != 1)
     break;
   if(i==1)
   {
   ...
   }
   else if ( i==2)
     traverse(temp);
 }
 while(i!=3);

知道用户想要什么(我未在您的代码中初始化)

创建

  scanf("%s", &c);

是错误的,因为 c char 而不是字符串

请勿将读取的 int char 混合使用,因为读取字符时会读取换行符和空格,因此请读取 c 的字符串,例如

char c[2];

...
scanf("%1s", &c);
if (*c == 'y')
  ...
else if (c == 'n')
  ...

else 分支中的 return 是无用的,并且如果答案不是'y'或'n',则您什么也不做,因此不设置临时,也许您只需要检查“ y”,其他所有答案都必须视为“ n”,或者您需要再次询问选择

create

分配局部变量 temps ,该变量对 main 中的 pb 没有影响,您需要获取一个node**例如

使用了 main 中的

,但从未在其他位置设置过,并且变量 j,k,l,m,n 是无用的。您还要求在 main 中输入数据,同时也要在 create 中进行输入,但不能在 main 中进行。管理变量的方式不允许您修改/打印列表

我鼓励您不要使用全局变量,并且不要像对 temp head 那样对全局变量和局部变量使用相同的名称因为那对您的代码阅读者没有帮助


解决问题的建议:

#include <stdlib.h>
#include <stdio.h>

struct node
{ 
  int a;
  struct  node * b;
};

/* flush input up to the end of the line */
void flush()
{
  int c;

  while ((c = getchar()) != '\n') {
    if (c == EOF)
      exit(-1);
  }
}

void create (struct node ** l)
{
  /* go to the end of the list */
  while (*l != NULL)
    l = &(*l)->b;

  for (;;) {
    char c[2];
    int v;

    printf("enter data\n");

    if (scanf("%d", &v) != 1) {
      puts("invalid value");
      flush();
    }
    else {
      *l = malloc (sizeof(struct node));
      (*l)->a = v;
      (*l)->b = NULL;
      l = &(*l)->b;

      for (;;) {
        printf("do you want to insert another node y/n\n");
        scanf("%1s", c);

        if (*c == 'y')
          break;
        else if (*c == 'n')
          return;
      }
    }
  }
}

void traverse ( struct node *head)
{
   while(head != NULL)
   {
     printf("%d ",head->a);
     head = head->b;
   }
   putchar('\n');
}

int main ()
{
  int i;
  struct node *head = NULL;

  for (;;) {
    puts("enter choice : 1 to create new node, 2 to print list, 3 to exit");

    if (scanf("%d", &i) != 1)
      flush();

    switch(i) {
    case 1:
      create(&head);
      break;
    case 2:
      traverse(head);
      break;
    case 3:
      return 0;
    default:
      break;
    }
  }
}

编译和执行:

/tmp % gcc -pedantic -Wextra -Wall t.c
/tmp % ./a.out
enter choice : 1 to create new node, 2 to print list, 3 to exit
2

enter choice : 1 to create new node, 2 to print list, 3 to exit
1
enter data
11
do you want to insert another node y/n
y
enter data
22
do you want to insert another node y/n
n
enter choice : 1 to create new node, 2 to print list, 3 to exit
2
11 22 
enter choice : 1 to create new node, 2 to print list, 3 to exit
1
enter data
3
do you want to insert another node y/n
n
enter choice : 1 to create new node, 2 to print list, 3 to exit
2
11 22 3 
enter choice : 1 to create new node, 2 to print list, 3 to exit
4
enter choice : 1 to create new node, 2 to print list, 3 to exit
3

我建议您添加免费列表

答案 1 :(得分:0)

我尝试使其尽可能简单,并保持逻辑不变。

#include <stdio.h>
#include <stdlib.h>

struct node
{
    int data;
    struct  node *next;
};

// create a new node
struct node* create(int data)
{
    struct node *n = malloc(sizeof(struct node));
    n->data = data;
    n->next = NULL; // by default its not NULL, so we must set it
    return n;
}

void traverse(struct node *head)
{
    struct node *tmp = head;
    while(tmp != NULL)
    {
        printf("%d\t",tmp->data);
        tmp = tmp->next;
    }
}

void cleanup(struct node *head)
{
    struct node *cur = head;
    struct node *next;

    while(cur != NULL)
    {
        next = cur->next;
        free(cur);
        cur = next;
    }
}

int main ()
{
    int data;
    struct node *head, *tmp;

    // head node is always created
    printf("enter data\n");
    scanf("%d",&data);
    head = tmp = create(data);

    if(head == NULL) return -1;

    // now we loop until we don't want to create any more nodes
    while(1)
    {
        char another;

        printf("do you want to insert another node y/n\n");
        scanf(" %c", &another); // ignore all the previous whitespace

        if(another == 'y')
        {
            printf("enter data\n");
            scanf("%d",&data);

            tmp->next = create(data);
            tmp = tmp->next;
        }
        else break;
        /*
         // anything but 'y' breaks the loop, but it can be set to continue if neither 'y' nor 'n' was read:
         else if(another == 'n') break;
         else continue;
         */
    }

    traverse(head);
    cleanup(head);
}

编辑:正如@Diodacus所说,我添加了清理功能并检查malloc是否返回NULL

答案 2 :(得分:0)

这里有几个问题:

struct node
{ 
  int a;
  struct  node *b;
} p,*temp,*head;

为什么要声明全局变量并将其用作函数参数?全局变量在全局范围内可用,无需将其传递给函数。另一方面,应避免全局变量并谨慎使用,因此最好创建局部变量(例如在main函数中)并将其作为参数传递给下一个函数。

void create ( struct node *temp)
{
  char c;

  temp = malloc (sizeof(struct node));

  printf("enter data\n");

  scanf(" %d",&temp->a);

  printf("do you want to insert another node y/n\n");

  scanf("%s", &c);
  if (c=='y')
  {
    create(temp->b);
  }
  else if ( c=='n')
  {
     temp->b= NULL;
     temp=&p;
     return;
   }
}

此功能看起来不对。 temp函数参数实际上是内部函数的变量,而不是输入/输出参数。在这种情况下,您可以分配给temp变量,但不会分配给列表。此外,temp函数参数阴影temp全局变量。返回操作状态也是一个好主意,通常'0'表示没有错误,还有其他任何错误值。

另一件事是使事情尽可能简单。这将允许更多的可重用性,并遵循单一责任原则。如果函数实际执行两个任务,则应将其分为两个函数。

还有一件事,您可以动态分配内存,但永远不会释放内存。这将导致内存丢失。

您的列表的可能实现方式可能是:

#include <stdio.h>
#include <stdlib.h>

typedef struct _node_t
{
  int a;
  struct _node_t * next;
} node_t;

static node_t * head = NULL;
static node_t * tail = NULL;

node_t * create(void)
{
  node_t * temp = malloc(sizeof(node_t));
  if (NULL == temp)
  {
    return NULL;
  }

  printf("Enter data\n");
  scanf("%d", & temp->a);
  return temp;
}

void append(node_t * data)
{
  if (NULL == head)
  {
    head = tail = data;
  }
  else
  {
    tail->next = data;
    tail = tail->next;
  }
  tail->next = NULL;
  return;
}

int add_data(void)
{
  node_t * data = NULL;
  char answer = 'y';

  data = create();
  if (NULL == data)
  {
    return 1;
  }
  append(data);
  return 0;
}

void traverse(void)
{
  node_t * current = NULL;

  for (current = head; current != NULL; current = current->next)
  {
    printf("%d ", current->a);
  }
  printf("\n");
  return;
}

void cleanup(void)
{
  node_t * current = head;

  while (NULL != current)
  {
    head = head->next;
    free(current);
    current = head;
  }
  return;
}

int main(int argc, char ** argv)
{
  int option = 3;

  do
  {
    printf("Enter option:\n  1 - add data\n  2 - traverse list\n  3 - exit\n\n");
    scanf("%i", & option);

    switch (option)
    {
      case 1:
        if (0 != add_data())
        {
          printf("ERROR:: Cannot allocate memory.\n");
          cleanup();
          return 1;
        }
        break;
      case 2:
        traverse();
        break;
      default:
        if (option > 3)
        {
          printf("ERROR:: Improper option, try again.\n");
        }
        break;
    }
  }
  while (option != 3);

  cleanup();
  return 0;
}