【问题标题】:Problems with pointers in c - linked listc - 链表中的指针问题
【发布时间】:2019-02-13 16:49:14
【问题描述】:

这是我的代码(处理链表):

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

typedef struct list{
   node_t* head;
} list_t;

node_t* create_node(void){
   node_t* tmp = malloc(sizeof(node_t));
   if (tmp == NULL){
      fprintf(stderr, "Error while allocating memory for node\n");
      exit(EXIT_FAILURE);
   }
   return tmp;
}

void list_insert(list_t* list, node_t* node, int data){
   if (node == NULL){
      node_t* new = create_node();
      new->next = list->head;
      list->head = new;
      new->data = data;
   }
   else{
      node_t* current = list->head;
      while(current != node){
         current = current->next;
      }
      node_t* new = create_node();
      new->next = current->next;
      current->next = new;
      new->data = data;
   }
}

我确实在 list_insert 函数中收到了一些警告,但我无法弄清楚它们的原因。如果作为参数传递的nodeNULL,则该函数应该在开头插入一个新节点,否则它应该在作为参数传递的node 之后插入一个新节点。

在这个sn-p中:

if (node == NULL){
   node_t* new = create_node();
   new->next = list->head;
   list->head = new;
   new->data = data;
}

分配new->next = list->head; 不正确。有什么猜测吗?

【问题讨论】:

  • 如果您收到警告,请先解决这些问题。如果您需要这方面的帮助,请在您的问题中说明您收到了哪些警告。
  • 在列表中查找node的循环也应该处理到达列表末尾但没有找到node的情况。
  • 这是多次重复,但与以往一样,困难在于找到正确的副本。我不确定是否有规范的问答。 Typdefs, tagged and untagged structures, and incompatible pointer types 密切相关,但并不完全相同(处理标签的存在/不存在,而不是直接处理拼写错误的标签导致混淆)。
  • 如果您有兴趣,我将您的程序的更正/修改版本,并附上执行示例
  • Enable Compiler Warnings,对于 gcc/clang,最小 -Wall -Wextra -pedantic,对于 VS /W3,并且在编译没有警告之前不要接受代码。 (只要遵循这条规则,你就会为自己节省无数时间)让你的编译器帮助你编写更好的代码。编译器会告诉你有问题的代码的确切行(通常是确切的起始字符)。永远不要忽视警告。

标签: c


【解决方案1】:

在你对struct node的定义中:

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

您将next 定义为指向struct node_t 的指针,但没有这种类型。你要struct node:

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

【讨论】:

    【解决方案2】:

    你不需要typedef struct list{ ...},你只需要一个node_t *类型的变量,它总是包含列表的头部,当它为空时为NULL。

    例如:

    #include <stdlib.h>
    #include <stdio.h>
    
    typedef struct node {
      int data;
      struct node * next;
    } node_t;
    
    node_t* create_node(int data)
    {
      node_t* tmp = malloc(sizeof(node_t));
    
      if (tmp == NULL){
        fprintf(stderr, "Error while allocating memory for node\n");
        exit(EXIT_FAILURE);
      }
      tmp->data = data;
      tmp->next = NULL;
      return tmp;
    }
    
    void list_append(node_t ** l, node_t* node){
      if (*l == NULL) {
        *l = node;
      }
      else {
        while ((*l)->next != NULL)
          l = &(*l)->next;
    
        (*l)->next = node;
      }
    }
    
    /* l, *l, where and node must not be NULL */
    int list_insert(node_t ** l, node_t* where, node_t* node) {
      if (*l != where) {
        for (;;) {
          if (*l == NULL)
            return 0;
          l = &(*l)->next;
          if (*l = where)
            break;
        }
      }
    
      node->next = *l;
      *l = node;
      return 1;
    }
    
    void pr(node_t * l)
    {
      printf("list is :");
      while (l != NULL) {
        printf(" %d", l->data);
        l = l->next;
      }
      putchar('\n');
    }
    
    void clear(node_t ** head)
    {
      node_t * l = *head;
    
      while (l != NULL) {
        node_t * n = l->next;
        free(l);
        l = n;
      }
    
      *head = NULL;
    }
    
    int main()
    {
      node_t * head = NULL;
      node_t * n3 = create_node(3);
    
      list_append(&head, create_node(1));
      list_append(&head, n3);
      pr(head);
    
      list_insert(&head, n3, create_node(2));
      pr(head);  
    
      list_insert(&head, head, create_node(0));
      pr(head);
    
      clear(&head);
      pr(head);
    
      return 0;
    }
    

    我改了创建当时可以给数据,这样更清楚(就像C++中的构造函数)

    编译和执行:

    pi@raspberrypi:/tmp $ gcc -pedantic -Wextra c.c
    pi@raspberrypi:/tmp $ ./a.out
    list is : 1 3
    list is : 1 2 3
    list is : 0 1 2 3
    list is :
    pi@raspberrypi:/tmp $ valgrind ./a.out
    ==27963== Memcheck, a memory error detector
    ==27963== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
    ==27963== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
    ==27963== Command: ./a.out
    ==27963== 
    list is : 1 3
    list is : 1 2 3
    list is : 0 1 2 3
    list is :
    ==27963== 
    ==27963== HEAP SUMMARY:
    ==27963==     in use at exit: 0 bytes in 0 blocks
    ==27963==   total heap usage: 5 allocs, 5 frees, 1,056 bytes allocated
    ==27963== 
    ==27963== All heap blocks were freed -- no leaks are possible
    ==27963== 
    ==27963== For counts of detected and suppressed errors, rerun with: -v
    ==27963== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
    

    【讨论】:

    • 非常好的验证valgrind
    • valgrind 是一个很棒的工具,人们必须知道它的存在,我尽我所能将执行放在它下面。
    猜你喜欢
    • 2023-03-13
    • 2011-05-16
    • 2020-05-28
    • 2019-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多