我有一个通用的链接列表保存类型为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:
我觉得你的问题是这样的:
- 你已经分配
secondList
在原始堆栈上test2
功能。 - 堆栈内存可能是脏的,所以
secondList
需要初始化 - 你
accList_allocate
功能需要一个指针到列表中,但随后在其覆盖Malloc
调用。 这意味着,你传递的指针永远不会初始化。 - 当
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