【问题标题】:Whether code is read from top to bottom代码是否从上到下读取
【发布时间】:2013-11-28 20:45:57
【问题描述】:

我正在 c 中创建一个基于链表的程序,其中每个节点(结构)都包含一个整数和一个指向下一个节点的指针。

在添加新节点和删除旧节点时,我使用动态分配 (malloc) 和释放 (free)。

当一个节点被删除时,一个名为 delete 的函数会被调用。

我发现程序有时会在调用此删除函数时崩溃,我知道它与方法中的指针有关,但我不知道代码中的位置(行号)以及为什么会发生这种情况。

我习惯了 Java 等高级语言,我习惯于通过在方法中的某些位置放置打印语法来解决问题,只是为了显示它崩溃的位置。 我想我可以用 c 和指针做同样的事情,因为据我所知,我相信代码是从上到下读取的,即 1、2、3、4 等等。 (也许中断处理程序的行为方式不同?)

所以在这个名为 delete 的函数中,到目前为止,我已经把这个 printf() 放在了 delete 函数的最开始处——但程序还是崩溃了。 em>

所以我的问题 - 是否真的有可能它在删除函数中的某些语法(例如当我循环指针时)导致崩溃,甚至 printf() 都没有打印? em>

当我认为程序是从下到下执行时,我错了吗 - 即 1, 2, 3 ....

你可以在delete-function的最开始设置我的printf-function

顺便说一句 - 当我从 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;
}

【问题讨论】:

    标签: c pointers crash


    【解决方案1】:

    常见错误,这是交易。这个

            printf("IN THE BEGINNING OF DELETE!!!");
    

    需要

            printf("IN THE BEGINNING OF DELETE!!!\n");
                                                 ^^ note the newline
    

    原因是 stdio 在看到换行符之前不会刷新 stdout。如果您添加该换行符,您应该在代码进入函数时看到 printf。没有它,程序可能会崩溃,stdout 缓冲区不会被刷新,也不会看到 printf。

    【讨论】:

      【解决方案2】:

      您的代码似乎有很多实现缺陷。作为一般建议,我建议使用一些经过充分测试的标准队列支持库和静态代码分析器(在这种情况下,您甚至会发现动态分析器 valgrind 非常有用,我猜)。

      例如,如果 destroy_node(ptr) 的实现等价于 free(ptr),那么您的代码会因引用被破坏的数据而受到影响(或者,换句话说,垃圾)在这段代码sn-p中:

              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 框中的神秘消息 - 当程序崩溃时,操作系统基本上会生成 crashdump 并打印寄存器(并转储一些相关的内存部分)。寄存器和内存转储可以显示崩溃的位置和立即寄存器/堆栈值,但您现在必须通过内存映射和汇编器输出来理解它。 Crashdump 可以与未剥离的二进制文件一起加载到调试器 (WinDbg) 中,以在崩溃时检查 stactrace 和局部变量的值。所有这些我都非常简单地描述了,你可以找到大量搜索“windows crash or crashdump analysis”的书籍/指南

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多