我有一个通用链接列表,其中包含void *类型的数据我试图用类型struct employee填充我的列表,最终我想破坏对象struct employee。
考虑这个通用的链表头文件(我用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: %sn", ((struct employee*)secondList.head->data)->name); //cast to type struct employee printf("Employee2: %sn", ((struct employee*)secondList.tail->data)->name); }
为什么我在下面发布的答案解决了我的问题? 我相信它与指针和内存分配有关。 我使用的函数Malloc()是一个自定义malloc,它检查返回的NULL。
这是我的整个通用链表实现的链接: https : //codereview.stackexchange.com/questions/13007/c-linked-list-implementation
问题是这个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; }
我认为你的问题是这样的:
在main
分配它时它起作用的原因是你的C编译器可能在程序启动时将堆栈归零。 当main
在堆栈上分配一个变量时,该分配是持久的(直到程序结束),所以当你在main
分配它时, secondList
实际上并且意外地正确初始化了。
您当前的accList_allocate
实际上并未初始化传入的指针,其余代码将永远不会看到它使用Malloc
分配的指针。 为了解决您的问题,我将创建一个新函数: accList_initialize
其唯一的工作是初始化列表:
void accList_initialize(struct accList* theList) { // NO malloc theList->head = NULL; theList->tail = NULL; theList->size = 0; }
在原始test2
函数中使用this而不是accList_allocate
。 如果你真的想在堆上分配列表,那么你应该这样做(而不是将它与在堆栈上分配的结构混合)。 让accList_allocate
返回指向已分配结构的指针:
struct accList* accList_allocate(void) { struct accList* theList = Malloc( sizeof(struct accList) ); accList_initialize(theList); return theList; }
当我在main()中放置secondList的声明和分配,并将其余部分放在一个函数中时,它可以工作:
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: %sn", ((struct employee*)secondList->head->data)->name); //cast to type struct employee printf("Employee2: %sn", ((struct employee*)secondList->tail->data)->name); removeData(emp, secondList); printf("Head: %sn", ((struct employee*)secondList->head->data)->name); } struct employee { char name[20]; float wageRate; }
这是整个实现的链接。
我觉得这与指针和分配有关。 有人可以向我解释那部分吗? 将问题中的代码与上面的代码进行比较。
谢谢!
根据原始代码我在这里看到的两件事是错的,在上面的问题中,
您所看到的是未定义的行为,并且由此产生的是总线错误消息,因为您正在为变量分配字符串文字,实际上您应该使用strcpy
函数,因此您已经按照原样编辑了原始代码。 。将来要记住的事情:)
使用Malloc
这个词会引起混淆,特别是在同行评审中,评论者会有一个大脑屁并说“哇,这是什么,不应该是malloc吗?” 并很可能提高它。 (基本上,不要调用具有与C标准库函数类似的声音名称的自定义函数)
你没有检查NULL
,如果你的加强版的Malloc
失败了那么emp
将会是NULL
! 总是检查一下无论多么微不足道或你的想法是“啊,这个平台上有大量的内存,4GB RAM没问题,不会费心去检查NULL”
看看其他地方发布的这个问题来解释什么是总线错误。
编辑:使用链表结构,如何调用函数中的参数对于理解它是至关重要的。 注意&的用法,意思是获取指向链表结构的变量的地址 ,并通过引用传递它 ,而不是传递作为变量副本的值。 同样的规则同样适用于指针的使用:)
你在问题的第一个代码中有一些参数稍微&secondList
,如果你在参数列表中使用双指针然后是,使用&secondList
就可以了。
这可能取决于您的员工结构的设计方式,但您应该注意到这一点
strcpy(emp->name, "Dan");
和
emp->name = "Dan";
function不同。 特别是,后者可能是总线错误的来源,因为您通常无法以这种方式写入字符串文字。 特别是如果您的代码有类似的东西
name =“NONE”
等等。
编辑:好的,所以对于员工结构的设计,问题是:
您无法分配给arrays。 C标准包括可修改的左值列表,而arrays不是其中之一。
char name[20]; name = "JAMES" //illegal
strcpy很好 – 它只是去名称[0]取消引用的内存地址,并将“JAMES 0”复制到那里的内存中,一次一个字节。
需要了解更多c/c++开发分享C通用链表,也可以关注C/ C++技术分享栏目—计算机技术网(www.ctvol.com)!
以上就是c/c++开发分享C通用链表相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/979459.html