ç通用链表(C generic linked-list)

2019-07-30 02:27发布

我有一个通用的链接列表保存类型为void *我想填充我名单与结构型员工数据,最终我想销毁的对象结构的员工也是如此。

考虑这种通用的链表头文件(我有一个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; 
} 

现在考虑这个样本的测试用例将从主被称为():

    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

Answer 1:

问题是这样的accList_allocate()和你对它的使用。

struct accList secondList;
accList_allocate(&secondList);

在原始TEST2()secondList在堆叠存储器。 &secondList是一个指针,指向存储器中。 当你调用accList_allocate()指针的副本在堆栈内存指着过去了。 的malloc(),然后返回的内存块,并将其分配到指针,而不是原来的secondList的副本。

回来了,secondList仍然在未初始化的内存堆栈上的指点,以便调用appendToEnd()失败。

同样的情况除外secondList答案恰好是免费的垃圾。 也许是偶然,可能是由编译器的设计。 无论哪种方式,是不是你应该依靠。

或者:

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


Answer 2:

我觉得你的问题是这样的:

  1. 你已经分配secondList在原始堆栈上test2功能。
  2. 堆栈内存可能是脏的,所以secondList需要初始化
  3. accList_allocate功能需要一个指针到列表中,但随后在其覆盖Malloc调用。 这意味着,你传递的指针永远不会初始化。
  4. test2尝试运行,它击中一个坏的指针(因为内存未初始化)。

它,当你在分配它的工作原理的原因main是,你的C编译器可能归零堆栈中的程序启动时。 当main分配堆栈上的变量,即分配是持久的(直到程序结束),所以secondList实际上,一不小心,当你将它分配正确初始化main

您当前的accList_allocate实际上并不初始化一个已经传入的指针,你的代码的其余部分将永远不会看到它与分配指针Malloc 。 为了解决你的问题,我会创造一个新的功能: accList_initialize其唯一的工作就是初始化列表:

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

利用这一点,而不是accList_allocate在原始test2功能。 如果你真的想在堆上分配列表,那么你应该这样做(而不是在栈上分配的结构混合的话)。 有accList_allocate 返回一个指向分配结构:

struct accList* accList_allocate(void)
{
   struct accList* theList = Malloc( sizeof(struct accList) );
   accList_initialize(theList);
   return theList;
}


Answer 3:

当我把secondList在main(申报和分配),并把其余的在它工作的函数:

int main(int argc, char *argv[])
{
  struct accList secondList;
  accList_allocate(&secondList);

  test2(&secondList);

  return 0;
}

void test2(struct accList *secondList)
{
  struct employee *emp = Malloc(sizeof(struct employee));
  struct employee *emp2 = Malloc(sizeof(struct employee));

  strcpy(emp->name, "Dan");
  emp->wageRate = .5;
  appendToEnd(emp, secondList);

  strcpy(emp2->name, "Stan");
  emp2->wageRate = .3;
  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);  
  removeData(emp, secondList);
  printf("Head: %s\n", ((struct employee*)secondList->head->data)->name);
}

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

下面是对整个执行的链接。 https://codereview.stackexchange.com/questions/13007/c-linked-list-implementation

我已经感觉这个事做指针和分配。 可能有人解释说,一部分给我吗? 在问题的代码进行比较,以上面这段代码。

谢谢!



Answer 4:

有两件事情我看到在原有基础上的代码错在这里,在上面的问题,

什么,你所看到的是未定义的行为,并出现从是你分配一个字符串给变量的时候,其实你应该使用一直是总线错误信息strcpy功能,编辑完你的原码accordinly左右。 。东西要记住在未来:)

这个词的使用Malloc会造成混乱,特别是在同行评议,评审将有脑屁,说“哇,这是什么,应该是不会的malloc?” 并且很可能要把它重建起来。 (基本上不叫有类似的名字听起来像C标准库函数的自定义函数)

你不检查为NULL ,如果你的改装成了版本Malloc失败则emp将是NULL ! 经常检查它,不管多么微不足道或你的思维“啊谢尔平台有它内存堆,4GB内存没有问题,不会刻意去检查NULL”

看看这个问题,其他地方张贴解释什么是总线错误。

编辑:使用链表结构,在函数的参数被称为是如何它的理解是至关重要的。 注意的使用,这意味着取指向该链接的表结构中的变量的地址 ,并通过引用将其传递 ,而不是由值是变量的副本传递 。 此规则同样适用于指针的使用也一般:)

你已经在第一代码得到的参数略有出来的地方在你的问题,如果你在参数列表中使用双指针则是,使用&secondList会工作。



Answer 5:

这可能取决于你的员工结构是如何设计的,但你要注意,

strcpy(emp->name, "Dan");

emp->name = "Dan";

功能不同。 特别是,后者是总线错误的可能来源,因为你一般不能写这样的字符串文字。 特别是如果你的代码中有类似

NAME = “NONE”

等。

编辑:好的,所以与员工结构的设计,问题是这样的:

你不能分配给数组。 C标准包括可修改的左值的列表和数组不是它们中的一个。

char name[20];
name = "JAMES" //illegal

strcpy的是好的 - 它只是变成由名称[0]和拷贝“詹姆斯\ 0”引用到存储在那里,一个字节在一个时间内存地址。



文章来源: C generic linked-list