如何在此 c 代码中找到分段错误?

Posted

技术标签:

【中文标题】如何在此 c 代码中找到分段错误?【英文标题】:How can I find the segmentation fault in this c code? 【发布时间】:2022-01-09 04:24:48 【问题描述】:

当我运行程序时,它会输出:

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV) 我找不到问题。

我尝试调试它,但我没有足够的c经验,无法找到错误。

代码要做的就是先随机创建一棵树,然后对所有节点的值求和。

另外,我真的需要知道如何编写更安全的 c 代码,而不会出现分段错误和此类问题。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


/**
 * Tree structure, where there can be any number of children
 */
typedef struct Tree 

    /**
     * Value of current node
     */
    double value;

    /**
     * number of children
     */
    int n;

    /**
     * children
     */
    struct Tree **children;
 Tree;


Tree *create(double value, int n) 
    Tree *tree = (Tree*) malloc(sizeof(Tree));
    int i;

    *tree = (Tree) 
        .value = value,
        .n = n,
        .children = NULL
    ;

    if (n) 
        tree->children = (Tree**) malloc(sizeof(Tree*));

        for (i = 0; i < n; i++) 
            tree->children[i] = NULL;
        
    

    return tree;



Tree *make_random_tree(int height) 
    double value;
    int n, i;
    Tree *tree;

    value = (rand() / (double) RAND_MAX) * 100.0;
    n = rand() % 10;


    if (height == 0) 
        return create(value, 0);
    

    tree = create(value, n);

    for (i = 0; i < n; i++) 
       tree->children[i] = make_random_tree(height - 1);
    

    return tree;



void delete(Tree *tree) 
    int i;

    if (tree == NULL) return;

    for (i = 0; i < tree->n; i++) 
        delete(tree->children[i]);
    

    free(tree->children);
    free(tree);



double sum_tree_values(Tree *tree) 
    double sum = 0.0;
    int i;

    if (tree == NULL) return 0.0;

    sum += tree->value;
    for (i = 0; i < tree->n; i++) 
        sum += sum_tree_values(tree->children[i]);
    

    return sum;



int main() 
    Tree *tree = make_random_tree(3);


    delete(tree);

    return 0;

【问题讨论】:

您是否能够在调试器中运行代码,以便查看发生分段错误的源代码行?如果您在 Linux 上,只需 (1) 在编译时添加 -g 标志,(2) 调用 gdb myprogram,以及 (3) 键入 run。你的程序应该可以运行,但是现在,当它崩溃时,gdb 应该会告诉你它在哪一行。输入bt 应该会给你一个堆栈回溯,显示是什么函数调用让你到达那个点。 查找“valgrind”,它将为您节省大量时间。 旁注:当这里的一位常客在不到一分钟的时间内发现您的问题时,他们就是这样做的。他们没有逐行检查您的代码并使用他们的 IR 视觉和 rad Skillz 检测错误——他们“作弊”,将您的代码复制粘贴到他们的机器上,并使用他们的编译器和调试器编译并运行它,并且他们就是这样发现问题的。 (“让计算机做脏活”,又名“懒惰是一种美德”。)但这就是为什么这里的人们总是如此坚持将代码作为文本而不是图像发布。 提示:malloc(sizeof(Tree*))分配了多少内存?如果把返回的指针当作一个数组,它会有多少个元素? 当我使用带有选项-g -fsanitize=address,undefined的GCC编译时,我得到这个内存访问错误:WRITE of size 8 at 0x602000000018 thread T0#0 0x558d513385e3 in create /home/main.c:42#1 0x558d513386d1 in make_random_tree /home/main.c:63#2 0x558d51338d35 in main /home/main.c:103...0x602000000018 is located 0 bytes to the right of 8-byte region [0x602000000010,0x602000000018)allocated by thread T0 here:... #1 0x558d5133848e in create /home/main.c:39 #2 0x558d513386d1 in make_random_tree /home/main.c:63 #3 0x558d51338d35 in main /home/main.c:103 ... 【参考方案1】:

您得到的错误是由访问不属于您的内存引起的。考虑使用valgrind 来查找这些错误

在:

Tree *create(double value, int n) 
    Tree *tree = (Tree*) malloc(sizeof(Tree));
    int i;

    *tree = (Tree) 
        .value = value,
        .n = n,
        .children = NULL
    ;

    if (n) 
        tree->children = (Tree**) malloc(sizeof(Tree*));

        for (i = 0; i < n; i++) 
            tree->children[i] = NULL;
        
    

    return tree;

您循环遍历 n 孩子并将它们设置为 NULL 但您只分配了 1 个孩子。您必须为所有孩子分配空间:

改变:

tree->children = (Tree**) malloc(sizeof(Tree*));

到:

tree->children = (Tree**) malloc(n * sizeof(Tree*));

进一步考虑使用calloc 而不是malloc,它会自动将所有子级设置为NULL

所以而不是:

if (n) 
        tree->children = (Tree**) malloc(n * sizeof(Tree*));

        for (i = 0; i < n; i++) 
            tree->children[i] = NULL;
        
    

使用:

if (n)
    tree->children = (Tree**) calloc(n, sizeof(Tree*));

【讨论】:

非常感谢!!! @i_iMatt 请刷新What should I do when someone answers my question?投票和/或接受。

以上是关于如何在此 c 代码中找到分段错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在此代码中调用虚拟方法时会出现分段错误?

带有 std::promise 的 C++11 分段错误

C 中 Trie 实现中的分段错误

sort函数C ++分段错误

python跟踪分段错误

C快速排序(链表)分段错误