2013-07-02 30 views
1

我正在测试比较器功能的实现。因此,这里是我的代码,工作正确执行C中的比较器功能不能按预期工作

#include <stdio.h> 
#include <string.h> 

int compare_names(const void* a, const void* b) 
{ 
    char* sa = (char*) a; 
    char* sb = (char*) b; 
    return strcmp(sa, sb); 
} 

int main() 
{ 
    char *a = "Bianca"; 
    char *b = "Ana"; 
    printf("Comparing %s with %s returns: %i\n", a, b, compare_names(a, b)); 
    return 0; 
} 

但我不认为这是在compare_names功能如右图ab参数应该变成是一个字符指针的指针。作为一本书我读过指出,为compare_names功能正确的代码将

int compare_names(const void* a, const void* b) 
{ 
    char** sa = (char**) a; 
    char** sb = (char**) b; 
    return strcmp(*sa, *sb); 
} 

但是,当我跑的代码,我得到了一个分段错误(核心转储)。

我在这里错过了什么?

编辑:我在Linux x64上使用gcc。

+1

可能您书中代码的上下文有所不同。使用不同的上下文(例如其他数据类型,其他数据关系和嵌套等),您可以(并将)获得不同的代码。 – glglgl

+1

假设书中的代码出现在qsort比较器或类似的环境中,那么这是有道理的。在这种情况下,它应该被称为'compare_names(&a,&b)'。 –

+0

@glglgl这就是我的想法。 – kaneda

回答

1
#include <stdio.h> 
#include <string.h> 

int compare_names(const void* a, const void* b) 
{ 
    char** sa = (char**) a; 
    char** sb = (char**) b; 
    return strcmp(*sa, *sb); 
} 

int main() 
{ 
    char *a = "Bianca"; 
    char *b = "Ana"; 
    printf("Comparing %s with %s returns: %i\n", a, b, compare_names(&a, &b)); 
    return 0; 
} 

现在没关系。您必须将ab的地址放在printf参数中,因为这些参数已被铸造为char**

+0

这有效,但我的第一次实施是瑕疵?如果不是的话,修正后的第二个解决方案要冗长得多。 – kaneda

+1

@kaneda你的第一个实现是正确的。这两个函数将产生相同的输出。在这种情况下,第二个在你的书中使用?第二个的唯一好处是你可以改变'a'和'b'的值。在你的情况下选择更方便。 – nouney

+0

带有void指针的版本看起来像是用于qsort();如果是这样的话,它的比较函数需要指向要排序的数组元素的原因,所以如果你有一个字符串数组,它将需要一个指针字符串(字符串是指向字符的指针) – loreb

1

char** sa = (char**) a;此行说:“如果你direference两次你sa你会最终有一个char”问题是,既然你a是字符指针不能direference两次。所以你所做的演员一般都是错误的。

铸造时,编译器改掉解释你的*a在进行转换你的*sa最后成了一个BadPtr,因为它未能从转换到charchar *char作为字符指针等等。

所以在你的strcmp()你有两个BadPtr。

1

您正在传递char *参数,而不是char **参数。您发布显示字符**的示例代码执行以下操作:

1. Change generic pointer to a pointer to a string. 
2. Compare the strings by dereferencing the char** arguments, meaning you're passing char* arguments to strcmp and return the result. 

但你传递的char *参数的比较功能,所以反引用最终传递char类型的参数到strcmp。由于它需要指针,所以char被解释为内存地址。将“hello”与“bye”比较实际上将地址0x67处的字符串与地址0x62处的字符串进行比较,这将会发生segfault。

通过& a和& b您的比较功能,使其不会段错误。

0

然而,这两个版本都适用于第二版“campare_names”函数,因此在调用函数时应该传递一个指向每个char指针的指针。

但是,您的函数版本是正确的,只有在您期望函数将改变指针位置或指向的数据时,才会使用双指针参数。在这种情况下,由于strcmp函数只读取char *数据并且不作任何更改,所以不需要附加指针。