Не удается сохранить элементы в связанном списке - PullRequest
0 голосов
/ 28 марта 2019

Моя цель - создать связанный список и хранить элементы внутри этого списка.

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 ]

3 голосов
/ 28 марта 2019

В main

 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);

, чтобы знать, чего хочет пользователь (я не инициализирован в вашем коде)

in create

  scanf("%s", &c);

неправильно, потому что c является char , а не строкой

Doне смешивайте чтение int и char , потому что вы будете читать символы новой строки и пробела при чтении символа, поэтому читайте строку для c , например

char c[2];

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

возврат в иначе ветвь бесполезна, и в случае, если ответ не 'y' или 'n', вы ничего не делаете, поэтому не устанавливаете temps , вероятно, вам нужно просто проверить, если 'y', и все остальные ответы следует считать 'n', или вам нужно снова спросить о выборе

в create вы назначаете локальную переменную temps , которая не влияет на pb в main , вам нужно получить node** например

in main temp используетсяно никогда не устанавливается в другом месте, а переменные j, k, l, m, n бесполезны.Вы также запрашиваете data в 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

Я призываю вас добавить свободный список

0 голосов
/ 28 марта 2019

Здесь есть несколько вопросов:

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 Параметр функции на самом деле является внутренней переменной функции, а не параметром in / out. В этом случае вы можете назначить переменную temp, но это не для списка. Также temp параметр функции shadows 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;
}
0 голосов
/ 28 марта 2019

Я попытался сделать это как можно проще и сохранить вашу логику там.

#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

...