2016-11-16 125 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

相关问题