【问题标题】:segfault when accessing function in struct访问结构中的函数时出现段错误
【发布时间】:2017-12-25 04:15:15
【问题描述】:

我正在尝试在红黑树上实现集合。我的树是用以下结构定义的:

typedef struct rb_tree {
int (*compare)(const void* a, const void* b); 
void (*destroy_key)(void* a);
void (*destroy_info)(void* a);
void (*print_key)(const void* a);
void (*print_info)(void* a);
rb_node* root;             
rb_node* nil;              
} rb_tree;

每当我尝试访问比较功能时,我都会遇到段错误。例如,在此辅助函数中的 if 语句中的比较中:

void tree_insert_help(rb_tree* tree, rb_node* z) {
rb_node* x;
rb_node* y;
rb_node* nil = tree->nil;

z->left = z->right = nil;
y = tree->root;
x = tree->root->left;
while( x !=  nil) {
    y = x;
    if (1 == tree->compare(x->key, z->key)) { /* x.key > z.key */ 
        x = x->left;
    } else { /* x,key < =  z.key  */
        x = x->right;
    }
}
z->parent = y;
if ( (y == tree->root) || (1 == tree->compare(y->key, z->key))) { /* y.key > z.key */
    y->left = z;
} else {
    y->right = z;
} 
}

这是我用来测试并从中获取段错误的代码。请注意,我有

typedef struct rb_tree *set; 
typedef struct rb_node *element;

在set.h中

#include "set.h"
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {;

int int_comp(const void* a,const void* b) {
  if( *(int*)a > *(int*)b) return(1);
  if( *(int*)a < *(int*)b) return(-1);
  return(0);
}
    void dfunc(void * a){
        free((int*)a);
    }
    void dinfo(void* a){
        ;
    }
    void print_int(int* a){
        printf("%d",*a);
    }
    set seta = new_set(int_comp, dfunc, dinfo, print_int, null_function);
    int x = 10;
    int y = 9;
    int z = 12;
    insert_element(seta, &x);
    insert_element(seta, &y);
    insert_element(seta, &z);
    print_set(seta);
}

此代码在第二次插入时失败,因为它调用了 tree->compare。使用 GDB 进行堆栈跟踪,我得到以下信息:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffffffde1b8 in ?? ()
(gdb) bt
#0  0x00007ffffffde1b8 in ?? ()
#1  0x0000000000400ce1 in TreeInsertHelp (tree=0x604010, z=0x604360) at red_black_tree.c:185
#2  0x0000000000400dce in RBTreeInsert (tree=0x604010, key=0x7ffffffde160, info=0x604340) at red_black_tree.c:233
#3  0x000000000040096b in insert_element (seta=0x604010, key=0x7ffffffde160) at set.c:22
#4  0x0000000000400848 in main (argc=1, argv=0x7ffffffde2c8) at test.c:38

此外,这实际上在 valgrind 中运行良好。这是我第一次在 c 结构中使用函数。我试图在其他地方查找这个问题,但调试它几乎没有进展。当我尝试访问树结构中的比较函数时,为什么会出现段错误?

编辑: New set 是以下函数的包装器,用于创建新树。

rb_tree* rb_tree_create( int (*comp_func) (const void*, const void*),
                void (*dest_func) (void*),
                void (*info_dest_func) (void*),
                void (*print_func) (const void*),
                void (*print_info)(void*)) {
rb_tree* new_tree;
rb_node* temp;

new_tree = (rb_tree*) safe_malloc(sizeof(rb_tree));
new_tree->compare = comp_func;
new_tree->destroy_key = dest_func;
new_tree->print_key = print_func;
new_tree->print_info = print_info;
new_tree->destroy_info = info_dest_func;

temp = (rb_node*) safe_malloc(sizeof(rb_node));
new_tree->nil = temp;
temp->parent = temp;
temp->left = temp;
temp->right = temp;
temp->red = 0;
temp->key = 0;
temp = (rb_node*) safe_malloc(sizeof(rb_node));
new_tree->root = temp;
temp->parent = new_tree->nil;
temp->left = new_tree->nil;
temp->right = new_tree->nil;
temp->key = 0;
temp->red = 0;
return(new_tree); 
}

编辑 2: 我解决了我的问题。我将指针传递给 new_set 的函数是在主函数中定义的。当我将它们移到主要功能之外时,它停止了段错误。

【问题讨论】:

  • new_set 显示。这也不是minimal reproducible example
  • ,缩进您的代码并在整个代码中始终使用indenting style。这样做会使它更加更容易阅读/维护。对您放置在 Stack Overflow 上的代码执行此操作会使用户更有可能对您的帖子进行投票,并且人们会花时间回答您的问题。您选择哪种样式并不重要(尽管对于某些语言,某些样式比其他样式更合适)。但是,选择一个一致地使用它用于单个项目中的所有代码。

标签: c pointers struct gdb function-pointers


【解决方案1】:

你已经创建了一个结构,“比较”是一个指向函数的指针。但它没有指向任何地方。 它应该在您的“new_set”函数中设置,但您没有显示它。

在您的“new_set”函数中,您应该执行以下操作:

... // new_set_struct is a struct that you've created and returning from new_set function
new_set_struct->compare = &int_comp;
... // all other new_set_struct initial configuration is following
return new_set_struct;

【讨论】:

  • 谢谢,我应该考虑在问题中包含 new_set 。当我设置指向函数的指针时,我需要使用 & 吗?我的印象是以下函数是等价的:new_set_struct->compare = &int_comp; 和 new_set_struct->compare = int_comp;
  • @user3210228.: 是的,它们是等价的。
猜你喜欢
  • 2014-05-31
  • 2020-05-14
  • 1970-01-01
  • 1970-01-01
  • 2020-12-26
  • 1970-01-01
  • 1970-01-01
  • 2016-05-05
相关资源
最近更新 更多