我在理解一段代码的工作原理时遇到了一些麻烦。以下是stdlib实现qsort的比较函数:
int scmp(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = (char *) p1;
v2 = (char *) p2;
return strcmp(v1,v2);
}
当然,这仅适用于字符串。我的问题是:为什么下面的代码有效?
int scmp(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = *(char **) p1;
v2 = *(char **) p2;
return strcmp(v1,v2);
}
在我看来,在第二个版本中,我强有力地将char*
显示为char**
到char
。问题是变量仍然包含*
变量的地址。当我应用p1
时,我理解C将通过获取char*
的内容来处理此命令,然后在存储在其中的地址之后读取8个字节(在我的拱门上),这样它就会最终得到handleChange(name, event)
类型的值。
在我看来,这应该导致将8个字符组合成无效的内存地址。
尽管如此,这两个功能同样有效。我哪里错了?
答案 0 :(得分:6)
假设您要使用int
对qsort
数组进行排序。
int numbers[] = {10, 50, 35, 62, 22};
首先,您创建一个可以比较两个int
的函数。
int intCompare(void* p1, void* p2)
{
int n1 = *(int*)p1;
int n2 = *(int*)p2;
return (n1 < n2);
}
然后,您可以使用:
qsort(numbers, 5, sizeof(int), intCompare);
当numbers
传递给qsort
时,它会被拒绝为int*
并传递为void*
。当我们需要从void*
中的intCompare
中提取数字时,我们需要在取消引用指针并比较值之前将其强制转换为int*
。
将这个比喻用于字符串,假设你想要排序:
char* strings[] = { "abc", "xyz", "def" };
对qsort
的调用将是:
qsort(strings, 3, sizeof(char*), scmp);
当strings
传递给qsort
时,它会被拒绝为char**
并传递为void*
。 scmp
传递给qsort
的指针的基础类型将是char**
,而不是char*
。因此,使用是正确的:
int scmp(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = *(char **) p1;
v2 = *(char **) p2;
return strcmp(v1,v2);
}
第一个版本在某些情况下由于幸运巧合而起作用。这是一个示例程序,它显示了几个不起作用的情况,而第二个版本应该始终有效。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// First version of scmp
int scmp1(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = (char *) p1;
v2 = (char *) p2;
return strcmp(v1,v2);
}
// Second version of scmp
int scmp2(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = *(char **) p1;
v2 = *(char **) p2;
return strcmp(v1,v2);
}
void test1()
{
char* strings[] = { "abc", "xyz", "def" };
qsort(strings, 3, sizeof(char*), scmp1);
for( int i = 0; i < 3; ++i )
{
printf("%s\n", strings[i]);
}
printf("\n");
}
void test2()
{
char* strings[] = { "abc", "xyz", "def" };
qsort(strings, 3, sizeof(char*), scmp2);
for( int i = 0; i < 3; ++i )
{
printf("%s\n", strings[i]);
}
printf("\n");
}
void test3()
{
char** strings = malloc(3*sizeof(char*));
strings[0] = "abc";
strings[1] = "xyz";
strings[2] = "def";
qsort(strings, 3, sizeof(char*), scmp1);
for( int i = 0; i < 3; ++i )
{
printf("%s\n", strings[i]);
}
free(strings);
printf("\n");
}
void test4()
{
char** strings = malloc(3*sizeof(char*));
strings[0] = "abc";
strings[1] = "xyz";
strings[2] = "def";
qsort(strings, 3, sizeof(char*), scmp2);
for( int i = 0; i < 3; ++i )
{
printf("%s\n", strings[i]);
}
free(strings);
printf("\n");
}
int main()
{
// Does not work.
test1();
// Should work always.
test2();
// Does not work.
test3();
// Should work always.
test4();
}
输出(使用gcc 4.8.4):
abc
xyz
def
abc
def
xyz
abc
xyz
def
abc
def
xyz