2013-07-24 41 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_typeexpr_IntegerLiteral枚舉和expr_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"

我不明白爲什麼我調用IntegerLiteral_init()的上下文會影響是否發生此段錯誤,如果給定的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時免費the_exp->expr

至於爲什麼IntegerLiteral_init()有時會出現正常工作,訪問內存還沒有分配導致不確定的行爲。有時你會很幸運,並且會立即崩潰,讓你可以使用調試器來查看問題的確切位置。其他時候你不那麼幸運,並且程序的執行還在繼續,只有當其他一些代碼嘗試訪問已損壞的內存IntegerLiteral_init()時纔會崩潰。

+0

你應該能夠只是改變'Expression'舉行'按值u_expr'然後使用結構引用操作符'.'到位結構引用操作'的 - >'。即'the_exp-> expr.intgr = intgr;' – simonc

+0

非常感謝,它現在正在工作。不僅如此,你糾正了我對工會的誤解。 – AlexJ136

2

它看起來像你沒有初始化u_expr *expr,它可能指向的內存,這將使你分段錯誤,如果你訪問它。