分段错误 - GNU C

3

我一直遇到一个无法解决的分段错误。导致分段错误的函数如下所示:

Expression *IntegerLiteral_init(int intgr) {
    Expression *the_exp = safe_alloc(sizeof(Expression));
    the_exp->type = expr_IntegerLiteral;
    the_exp->expr->intgr = intgr;
    the_exp->exec_count = 0;
    return the_exp;
}

表达式的定义:

typedef struct {
    expr_type type;
    u_expr *expr;
    int exec_count;
} Expression;

u_expr和expr_type已定义:

typedef union {
    char *ident;
    int intgr;
} u_expr;

typedef enum {
    expr_Identifier,
    expr_IntegerLiteral
} expr_type;

expr_type是一个由expr_IntegerLiteralexpr_Identifier组成的枚举。

根据GDB的显示,段错误是在这一行引起的:the_exp->expr->intgr = intgr;。奇怪的是,并不总是会导致段错误-只有当我以这种方式调用函数时才会出现:

Expression *e = IntegerLiteral_init(0);

但在程序的另一个部分,我使用以下方式调用它:

Expression *e;

...

e = IntegerLiteral_init(
    (int)strtol(num_str, (char **)NULL, 10));

这段代码可以正常运行。 num_str 是从某个输入中解析出的字符串,其值为"0".

如果给定的intgr参数相同,我不明白为什么调用 IntegerLiteral_init() 的上下文会影响此段错误。如果有人能够解释一下,我将非常感激。

2个回答

8

这是一行代码

the_exp->expr->intgr = intgr;

您正在向未初始化的指针写入数据。您已为the_exp分配了内存,但没有为the_exp->expr分配内存。最简单的解决方法可能是将Expression中的u_expr改为按值传递而不是按指针传递。

typedef struct {
    expr_type type;
    u_expr expr;
    int exec_count;
} Expression;

如果您无法完成此操作,可以更改 IntegerLiteral_init 以为 the_exp->expr 分配内存。
Expression *IntegerLiteral_init(int intgr) {
    Expression *the_exp = safe_alloc(sizeof(Expression));
    the_exp->type = expr_IntegerLiteral;
    the_exp->expr = safe_alloc(sizeof(*the_exp->expr));
    the_exp->expr->intgr = intgr;
    the_exp->exec_count = 0;
    return the_exp;
}

如果您尝试后一种方法,请确保在释放the_exp时也释放the_exp->expr
关于为什么IntegerLiteral_init()有时似乎有效,访问未分配的内存会导致未定义的行为。有时候你可能运气好,程序会立即崩溃,让你使用调试器精确定位问题所在。但其他时候运气不太好,当IntegerLiteral_init()破坏了内存后,程序执行可能会继续,只有在以后某个时刻,当某些其他代码尝试访问被破坏的内存时程序才会崩溃。

你应该能够只需将 Expression 更改为按值持有 u_expr,然后使用结构引用运算符 . 代替结构解引用运算符 ->。即 the_exp->expr.intgr = intgr; 可以改为 the_exp.expr.intgr = intgr; - simonc
非常感谢,现在它可以工作了。不仅如此,您还纠正了我对联合体的误解。 - AlexJ136

2

看起来你没有初始化u_expr *expr,它可能指向的内存如果被访问会导致分段故障。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接