我在c中创建一个基于链表的程序,其中每个节点(结构)都包含一个整数和一个指向下一个节点的指针。
我在添加新节点并删除旧节点时使用动态分配(malloc)和解除分配(免费)。
删除节点时,会调用名为 delete 的函数。
我发现程序有时会在调用这个delete函数时崩溃,我知道它与方法中的指针有关,但我不知道代码中的WHERE(行号)以及为什么会发生这种情况。
我习惯于使用Java等高级语言,我习惯于通过在方法中的某些位置放置print-syntax来解决问题,只是为了揭示它崩溃的地方。 我以为我可以用c和指针做同样的事情,因为据我所知,我相信代码是从上到下读取的,分别是1,2,3,4等等。 (也许中断处理程序表现另一种方式?)
所以在这个名为 delete 的函数中,我把这个printf()放在delete-function的最开头,并且所有程序都崩溃了。
所以我的问题 - 它是否真的有可能在删除函数中的某些语法(当我循环指针时)导致崩溃甚至printf()都没有打印?
当我相信程序从下到下执行时,我错了 - 那就是1,2,3 ....
你可以在delete-function
的最开头看到我的printf函数顺便说一句 - 当我从Windows获得这个神秘的崩溃消息时,我怎么能解决这个问题?看位图!!
很有帮助!!!
int delete(int data) {
printf("IN THE BEGINNING OF DELETE!!!");
int result = 0;
if (queueref.last != NULL) {
node *curr_ptr;
node *prev_ptr;
node *temp_ptr;
if (queueref.first->data == data) {
temp_ptr = queueref.first;
queueref.first = queueref.first->next;
destroy_node(temp_ptr);
result = 1;
if (queueref.first == NULL) {
queueref.last = NULL;
puts("queue is now empty!!!");
}
} else {
prev_ptr = queueref.first;
curr_ptr = queueref.first->next;
printf("prev_ptr: %d\n", prev_ptr);
printf("curr_ptr: %d\n", curr_ptr);
while(curr_ptr != NULL) {
if (curr_ptr->data == data) {
result = 1;
if (curr_ptr->next != NULL) {
temp_ptr = curr_ptr;
destroy_node(temp_ptr);
prev_ptr->next = curr_ptr->next;
} else {
temp_ptr = curr_ptr;
queueref.last = prev_ptr;
prev_ptr->next = NULL;
destroy_node(temp_ptr);
}
}
curr_ptr = curr_ptr->next;
prev_ptr = prev_ptr->next;
}
}
}
return result;
}
答案 0 :(得分:2)
常见错误,这是交易。此
printf("IN THE BEGINNING OF DELETE!!!");
需要
printf("IN THE BEGINNING OF DELETE!!!\n");
^^ note the newline
原因是因为stdio在看到换行符之前不会刷新stdout。如果添加该换行符,则应在代码进入函数时看到printf。没有它,程序可能会崩溃,stdout缓冲区不会被刷新,也不会看到printf。
答案 1 :(得分:1)
您的代码似乎有很多实现缺陷。作为一般建议,我建议使用一些经过良好测试的标准队列支持库和静态代码分析器(在这种情况下,您甚至会发现动态分析器valgrind非常有用,我猜)。
例如,如果 destroy_node(ptr)的实现等同于 free(ptr),那么您的代码会受到引用已销毁数据的影响(换句话说,垃圾)在这段代码片段中:
while(curr_ptr != NULL) {
if (curr_ptr->data == data) {
result = 1;
if (curr_ptr->next != NULL) {
temp_ptr = curr_ptr;
destroy_node(temp_ptr);
prev_ptr->next = curr_ptr->next; //<- curr_ptr is still in stack
//or register, but curr->next
//is garbage
// what if curr_ptr is first node? did you forget to update queueref.first?
} else {
temp_ptr = curr_ptr;
queueref.last = prev_ptr;
prev_ptr->next = NULL;
destroy_node(temp_ptr);
}
// if you you need to destroy only one node - you can leave the loop here with break;
}
curr_ptr = curr_ptr->next; /// assigning garbage again if node is found
prev_ptr = prev_ptr->next;
使用被破坏数据的原因可以在*大多数*(如果我可以说,基本上这是不可预测的)情况下,这个内存可以由程序的其他部分重用于动态分配数据的机会可能会有所不同时间和代码流。
PS
关于Windows框中的神秘消息 - 当程序崩溃时OS基本上会生成故障转储并打印寄存器(并转储一些相关的内存部分)。寄存器和内存转储可以显示崩溃的位置和立即寄存器/堆栈值,但您现在必须使用内存映射和汇编器输出来理解它。可以将Crashdump与未提取的二进制文件一起加载到调试器(WinDbg),以在崩溃时检查stactrace和局部变量的值。所有这些我都非常简短地描述,你可以找到大量的书籍/指南搜索“windows crash或crashdump analysis”