【问题标题】:Implementation of a string singly linked list in CC中字符串单链表的实现
【发布时间】:2020-11-25 15:51:53
【问题描述】:

我想在每个节点中创建一个包含字符串的单链表,而不是整数。

但是,我无法实现它。有人可以告诉我实施有什么问题吗?

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

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

struct node* create(struct node* head, const char* data) {
  struct node* newnode, * temp;
  newnode = (struct node*)malloc(sizeof(struct node));
  newnode->data = data;
  newnode->next = NULL;
  if (head == NULL) {
    head = newnode;
    temp = newnode;
  }
  else {
    temp->next = newnode;
    temp = temp->next;
  }
  temp->next = NULL;
  return head;
}

struct node* display(struct node* head) {
  struct node* temp;
  temp = head;
  while (temp != NULL) {
    printf("%d->", temp->data);
    temp = temp->next;
  }
  printf("NULL");
  return head;
}

int main() {
  struct node* head;
  head = NULL;
  int size, i;
  char str[5];
  printf("\nSize of linked list you want: ");
  scanf("%d", &size);
  for (i = 0; i < size; i++) {
    gets(str);
    head = create(head, str);
  }
  display(head);
  return 0;
}

【问题讨论】:

  • temp-&gt;next = newnode; 这里temp 尚未初始化。
  • 从不使用gets。即使是琐碎的玩具问题。 唯一 可以使用gets 的时间是在您演示gets 的问题时。不要使用它。
  • 您在另一个问题中使用了相同的 create 函数,我解释了为什么它不起作用。你可以在那里找到它,那是一天前的事。这次的额外问题是您在节点中存储了一个字符而不是字符串(char *)。当您在节点中放置一个 char * 时,您可能还想在插入时复制字符串,否则您将在测试代码中获得指向同一缓冲区的指针列表。

标签: c data-structures linked-list singly-linked-list


【解决方案1】:

char data 包含单个字符。这不是你想要的,对吧?你想保存一个字符串,即指向第一个字符的指针:

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

这通过指针保存字符串 - 不清楚您是否希望此指针成为拥有指针(即如果节点消失,则字符串也消失)或引用(即其他人拥有字符串并管理它的生命周期)。

还有其他错误,但这是一个很好的起点。并启用来自编译器的所有警告,并理解它们,因为如果你的代码,它们中的大多数都是 C 语言允许的错误(因为它不能确定你真正想要什么)——但这并不表示代码正确。

另一种保存字符串的方式可能是按值,也就是说,您可以保存一个数组 - see another answer to this question for how to do that,而不是像您在答案中那样只有一个字符。通过指针拥有字符串还是将其作为值拥有之间的选择在介绍性教学代码中并不重要,因为您不会在实际用例中测量数据结构的性能。所以没有“一个真正的选择”:每一个在某些用例中都有好处。

一些含糊的建议(总是要经过测量!)可能是:

  • 如果值是恒定的,那么按值将字符串保持为固定大小或可变大小通常会在性能上获胜

  • 如果值的大小范围很小(例如,所有字符串都是“短”),那么具有固定大小的节点并将其分配到连续的内存池中可能会提高性能

  • 如果值发生变化,那么按值保存字符串并不总是可行的:节点可能需要重新分配以调整它的大小,然后您需要一个双向链表来调整相邻节点的指针以反映新的节点地址

  • 最通用且可能性能最差的选项是通过拥有指针来保存字符串,因此节点可以保持在固定地址,但字符串可以移动;在这种情况下,如果有很多小字符串,小字符串优化可能会进一步改进:将字符串保存在节点的固定大小的 char 数组中(如果适合),否则将其分配在单独的内存块中;这就是std::string 的实现中通常所做的事情,它提高了性能。想法是,由于字符串是“大”的,因此与使用该字符串的实际值完成的任何工作相比,必须引用其他地址来获取其数据的开销将是微不足道的。

【讨论】:

    【解决方案2】:

    有几个问题:

    • 你的结构体中需要一个char 数组,而不是c char
    • create 函数过于复杂且错误

    您的display 函数是正确的。

    你想要这个:

    有关解释,请查看 cmets。

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAXSTRINGSIZE 100                  // maximum allowed size of strings
    
    struct node {
      char data[MAXSTRINGSIZE];                // we need an array of char her, not a char
      struct node* next;
    };
    
    struct node* create(struct node* head, const char* data) {
      struct node* newnode = malloc(sizeof(struct node));   // no cast is needed with malloc
      strcpy(newnode->data, data);             // copy the string
    
      newnode->next = head;  
      return newnode;
    }
    
    struct node* display(struct node* head) {
      struct node* temp;
      temp = head;
      while (temp != NULL) {
        printf("%s->", temp->data);
        temp = temp->next;
      }
    
      printf("NULL");
      return head;
    }
    
    int main() {
      struct node* head;
      head = NULL;
      int size;
      char str[MAXSTRINGSIZE];
      printf("\nSize of linked list you want: ");
      scanf("%d", &size);
    
      getchar();             // absorb \n, scanf and gets don't mix well
    
      for (int i = 0; i < size; i++) {
        gets(str);
        head = create(head, str);
      }
    
      display(head);
      return 0;
    }
    

    备注

    • 您可以使用指针并仅分配存储字符串所需的内存量,而不是在结构中使用固定大小的data 成员。我让你自己解决这个问题。
    • 您应该使用fgets,而不是gets,这是一个已弃用的函数。阅读this 了解更多信息。

    【讨论】:

      猜你喜欢
      • 2021-01-27
      • 2012-10-17
      • 2015-08-18
      • 2013-12-03
      • 2016-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-12
      相关资源
      最近更新 更多