2016-11-16 80 views
1

好,所以我只做了幾個星期的C,並且遇到了一些問題。我有一個填充Bsig指針的優先級隊列。作爲一個附加功能,我希望每當出現Bsig時,我們都會執行自定義功能。爲什麼我不能從C中的返回結構調用函數指針?

typedef struct bsig{ 
// some more fields here, but they're not important 
    struct onpop_t *on_pop; 
} Bsig; 

typedef struct onpop_t { 
    struct onpop_t *next; 
    int (*do_on_pop)(Bsig *caller); 
} Onpop; 

int pop(SigPQ *q, Bsig* ret_sig){ 
    if (q->size < 1){ 
     return 0; 
    } 
    Bsig* signal = q->signals[0]; 
    assert(signal); 
    q->signals[0] = q->signals[q->size-1]; 
    q->size--; 
    sigpq_heapify(q,0); 

    if(signal->on_pop){ 
     signal->on_pop->do_on_pop(signal); 
    } 
    ret_sig = signal; 
    return 1; 
} 

所以基本上,每當我們調用pop時,應該啓動do_on_pop函數。此外,pop會接收一個信號指針,該指針由隊列中彈出的任何內容覆蓋。所有這些都發生在main.c中包含的兩個文件中。以下是從主(其中testpop是伸出打印出一些東西隨機的自定義功能 - 它宣佈在main.c文件中定義):

Bsig *sig1 = new_signal(1000, 0); 
Onpop *onpop1 = malloc(sizeof(Onpop)); 
onpop1->do_on_pop = &testpop; 
sig1->on_pop = onpop1; 
push(pq, sig1); 

Bsig *ret_sig; 
pop(pq,ret_sig); 

到目前爲止好 - 自定義功能testpop被調用。但是

ret_sig->on_pop->do_on_pop(ret_sig); 

from main給出了段錯誤!我不明白爲什麼。 ret_sig地址和信號地址應該是相同的,並且函數調用是相同的 - 唯一的區別是一個是從main調用的,另一個是從包含的.c文件中調用的。任何人都可以流光?

+1

與調試C程序一樣,在調試器中運行程序並查看段錯誤發生的位置。還要檢查一些值;你是否在某處解除引用? –

+1

「主要給出分段錯誤」根本沒有足夠的信息來回答你的問題。要麼指定哪一行代碼給出了分段錯誤,要麼 - 最好 - 執行一些調試,更深入地調查這個問題,並且 - 如果仍然需要的話 - 返回一個更準確的描述你遇到的問題。如果我沒有解決它, –

+0

將返回更多信息。但是,我發現了ret_sig == NULL。謝謝,機器人評論:) :) –

回答

2

您需要明確地通過ret_sig作爲參考。

int pop(SigPQ *q, Bsig** ret_sig){ 
    if (q->size < 1){ 
     return 0; 
    } 
    Bsig* signal = q->signals[0]; 
    assert(signal); 
    q->signals[0] = q->signals[q->size-1]; 
    q->size--; 
    sigpq_heapify(q,0); 

    if(signal->on_pop){ 
     signal->on_pop->do_on_pop(signal); 
    } 
    *ret_sig = signal; 
    return 1; 
} 

又通的ret_sig

Bsig *ret_sig; 
pop(pq,&ret_sig); 

地址或改變函數返回而不是int的指針(它是清潔器):

Bsig *pop(SigPQ *q){ 
    if (q->size < 1){ 
     return NULL; 
    } 
    Bsig* signal = q->signals[0]; 
    assert(signal); 
    q->signals[0] = q->signals[q->size-1]; 
    q->size--; 
    sigpq_heapify(q,0); 

    if(signal->on_pop){ 
     signal->on_pop->do_on_pop(signal); 
    } 
    return signal; 
} 

並分配的返回值:

Bsig *ret_sig = pop(pq); 
+0

Nit picking:至少在語言層面上,在C. – alk

+0

@alk中沒有「*通過......參考*」。確實,C始終按值傳遞參數。在這種情況下,'&ret_val'是通過值傳遞的,它通過引用有效地(明確地)傳遞'ret_val'。 – pat

+0

除非你對數組進行計數,這些數組通過引用傳遞,因爲它們自動衰減爲指針。 – pat

相關問題