2013-07-24 7 views
3

У меня возникла ошибка сегментации, которую я не могу понять. Функция, которая вызывает ошибку сегментации приведен ниже:Ошибка сегментации - GNU C

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_IntegerLiteral и expr_Identifier.

Согласно GDB, segfault вызывается на линии: the_exp->expr->intgr = intgr;. Как ни странно, это не всегда приводит к Segfault - выдаёт ошибку сегментации происходит, если я вызываю функцию таким образом:

Expression *e = IntegerLiteral_init(0); 

Но в другой части моей программы, я называю его помощью:

Expression *e; 

... 

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

который работает без проблем. num_str был разобран с некоторого ввода и имеет значение "0".

Я не понимаю, почему контекст, в котором я звоню IntegerLiteral_init(), должен влиять на то, происходит ли этот segfault или нет, если данный параметр intgr тот же. Если бы кто-нибудь мог пролить свет на это, я был бы очень благодарен.

ответ

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; 

Если вы не можете сделать это, может быть изменен для выделения памяти для 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->expr, когда вы бесплатно the_exp.

Относительно того, почему IntegerLiteral_init() иногда работает, доступ к памяти, которую вы не выделили, приводит к неопределенному поведению. Иногда вам повезло, и это немедленно сбой, позволяя вам использовать отладчик, чтобы точно увидеть, в чем проблема. В других случаях вам менее повезло, и выполнение вашей программы продолжается, только для того, чтобы сбой позже, когда какой-то другой бит кода пытается получить доступ к памяти IntegerLiteral_init() поврежден.

+0

Вы должны просто изменить выражение «выражение», чтобы сохранить значение «u_expr», а затем использовать оператор ссылочной структуры '.' вместо оператора разметки структуры' -> '. то есть 'the_exp-> expr.intgr = intgr;' – simonc

+0

Спасибо, миллион, он работает сейчас.Не только это, вы исправили недоразумение, которое я имел о союзах. – AlexJ136

2

Похоже, что вы не инициализируете u_expr *expr, это, вероятно, указывает на память, которая даст вам ошибку сегментации, если вы ее получите.

Смежные вопросы