当前位置: 首页 > 知识库问答 >
问题:

C通用链表

石臻
2023-03-14

我有一个通用的链表,其中保存的数据类型为空*我试图填充我的列表与结构雇员类型,最终我想破坏对象结构雇员以及。

考虑这个通用的链接列表头文件(我已经用char*类型测试过了):

struct accListNode                 //the nodes of a linked-list for any data type
{
  void *data;                     //generic pointer to any data type
  struct accListNode *next;       //the next node in the list
};

struct accList                    //a linked-list consisting of accListNodes
{
  struct accListNode *head;
  struct accListNode *tail;
  int size;
};

void accList_allocate(struct accList *theList);           //allocate the accList and set to NULL
void appendToEnd(void *data, struct accList *theList);    //append data to the end of the accList
void removeData(void *data, struct accList *theList);         //removes data from accList
  --------------------------------------------------------------------------------------

考虑员工结构

struct employee 
{ 
   char name[20]; 
   float wageRate; 
} 

现在考虑从main()调用的示例测试用例:

    void test2()
    {
      struct accList secondList;
      struct employee *emp = Malloc(sizeof(struct employee));
      emp->name = "Dan";
      emp->wageRate =.5;

      struct employee *emp2 = Malloc(sizeof(struct employee));
      emp2->name = "Stan";
      emp2->wageRate = .3;

      accList_allocate(&secondList);
      appendToEnd(emp, &secondList);
      appendToEnd(emp2, &secondList);

      printf("Employee: %s\n", ((struct employee*)secondList.head->data)->name);   //cast to type struct employee
      printf("Employee2: %s\n", ((struct employee*)secondList.tail->data)->name);  
    }

为什么我在下面发布的答案解决了我的问题?我相信这与指针和内存分配有关。我使用的函数Malloc()是一个自定义Malloc,用于检查是否返回NULL。

下面是我的整个通用链表实现的链接:https://codereview.stackexchange.com/questions/13007/c-linked-list-implementation

共有3个答案

锺星腾
2023-03-14

在上面的问题中,根据原始代码,我认为有两件事是错误的,

您所看到的是未定义的行为,并由此产生的是总线错误消息,因为您正在为变量分配字符串文本,而实际上您应该使用strcpy函数,因此您已经相应地编辑了原始代码。

使用Malloc这个词会引起混乱,尤其是在同行评议中,评论者会有一个大脑屁,然后说“哇,这是什么,这不应该是Malloc吗?”而且很可能会把它抬高。(基本上,不要调用与C标准库函数名称相似的自定义函数)

您没有检查NULL,如果您的增强版Malloc失败了,那么emp将是NULL!无论多么琐碎或您的想法是“啊,她的平台上有大量内存,4GB内存没问题,不会费心检查为NULL”,请始终检查它

看看其他地方发布的这个问题,来解释什么是总线错误。

编辑:使用链表结构,如何调用函数中的参数对理解函数至关重要。注意

在问题的第一个代码中,参数有点不合适,如果在参数列表中使用双指针,那么是的,使用

阎宾实
2023-03-14

我认为你的问题是:

  1. 您已经在原始test2函数的堆栈上分配了第二个列表
  2. 堆栈内存可能是脏的,所以秒列表需要初始化
  3. 您的accList_allocate函数获取指向列表的指针,但随后用Malloc调用覆盖它。这意味着您传入的指针永远不会初始化。
  4. test2尝试运行时,它会碰到一个错误的指针(因为内存没有初始化)。

当您在main中分配它时,它起作用的原因是当程序启动时,您的C编译器可能会将堆栈归零。当main在堆栈上分配变量时,这种分配是持久的(直到程序结束),所以当您在main中分配它时,第二列表实际上是意外地正确初始化的。

您当前的accList_allocate实际上并没有初始化传入的指针,代码的其余部分将永远看不到它分配给Malloc的指针。为了解决您的问题,我将创建一个新函数:accList_initialize,它的唯一工作是初始化列表:

void accList_initialize(struct accList* theList)
{
    // NO malloc
   theList->head = NULL;
   theList->tail = NULL;
   theList->size = 0;
}

在原来的test2函数中,使用这个函数,而不是accList\u allocate。如果你真的想在堆上分配列表,那么你应该这样做(不要把它和在堆栈上分配的结构混在一起)。让accList\u allocate返回一个指向已分配结构的指针:

struct accList* accList_allocate(void)
{
   struct accList* theList = Malloc( sizeof(struct accList) );
   accList_initialize(theList);
   return theList;
}
申屠裕
2023-03-14

问题在于accList_allocate()和您对它的使用。

struct accList secondList;
accList_allocate(&secondList);

在最初的test2()中,第二个列表是堆栈上的内存。

返回后,secondList仍然指向堆栈上未初始化的内存,因此对appendToEnd()的调用失败。

同样的事情也会发生在答案上,除了第二个列表恰好没有垃圾。可能是偶然的,也可能是编译器的设计。不管怎样,它都不是你应该依赖的东西。

要么:

struct accList *secondList = NULL;

accList_allocate(&secondList);

并更改accList_allocate()

accList_allocate(struct accList **theList) {
    *theList = Malloc(sizeof(struct accList));
    (*theList)->head = NULL;
    (*theList)->tail = NULL;
    (*theList)->size = 0;
}

struct accList secondList;

accList_initialise(secondList);

accList_allocate()改为accList_initialise(),因为它不分配

accList_initialise(struct accList *theList) {
    theList->head = NULL;
    theList->tail = NULL;
    theList->size = 0;
}
 类似资料:
  • 本文向大家介绍C#通过链表实现队列的方法,包括了C#通过链表实现队列的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#通过链表实现队列的方法。分享给大家供大家参考。具体实现方法如下: 希望本文所述对大家的C#程序设计有所帮助。

  • 嘿,伙计们,我在让for循环工作时遇到了一些麻烦。myList是一个链表,其中填充了文件中的数字,我正在尝试遍历它并以一种(当前,下一个)的方式打印当前值和每个下一个值- 出于某种原因,for循环无法执行任何操作,或者更确切地说,代码在for循环的开始就中断了。如果我摆脱for循环并只是复制和粘贴 很多时候它会按照我的意愿工作,但我宁愿不这样做。for 循环语法看起来是正确的,如果 say cou

  • 所以我有一个堆栈,它允许典型的Push和Pop函数。我很难理解这一切实际上是如何在代码方面工作的。我在这里看到了这篇文章,最佳答案中的图片/图表,展示了列表是如何被“推”下来的,你指向最新的元素。我有一个 它挂接到结构“节点” 我如何结合一个推拉与"节点*下一步;"?最难理解的是我将如何真正做到这一点。我知道它最初指向空,然后如果我推一个2,4,6,它将是6,4,2,#。掌握如何实际使用链表中的指

  • 在试图理解如何在C#中实现单个列表时,我遇到了下面的链接: 创建一个非常简单的链表。 然而,由于我是C#的新手,我被上面讨论的第一部分中列出的语法弄糊涂了。正在声明一个名为节点的类,并且在声明为“公共节点下一个”的类中还有另一个语句。这个语句称为构造函数吗?请帮忙。

  • 众所周知,iOS深层链接已经改变了一点,称为通用链接,有了通用链接,我们需要在您的Xcode项目中启用“关联域”,并在那里添加受支持的域,还有一些变化,如在域服务器上托管苹果应用站点关联JSON。 这一点我非常理解,但我的问题是我必须支持多个社区,可能每个使用应用程序的企业都会有自己的社区,所以将所有社区(域)添加到“关联域”中不是一件好事,如果有新企业使用应用程序,然后我需要提供一个应用程序更新

  • 1.1.1. 目录 1.1.2. 一、概述 1.1.3. 二、硬件示例 1.1.4. 三、软件架构 1.1.5. 四、全链路集成 1.1.6. 五、API参考 1.1.1. 目录 一、概述 Rokid全链路通用方案 软件框架简介 二、硬件示例 三、软件架构 SDK目录结构 config doc executable android-libraries文件列表 shared-libraries文件列