void *idealGenericLSearch(void *key, void *base, int numElem, int elemSize,
int (*cmpfn)(void *, void *)) {
for (int i = 0; i < numElem; i++) {
void *elemAddr = (char *)base + (i * elemSize);
if (cmpfn(key, elemAddr) == 0)
return elemAddr;
}
return NULL;
}这是我正在使用的通用线性搜索函数。我正在搜索一个char *的数组。下面是我的比较函数:
int myStrCmp(void *vp1, void *vp2) {
char *s1 = *(char**)vp1;
char *s2 = *(char**)vp2;
return strcmp(s1, s2);
}我主要是这样称呼它的:
char *notes[] = { "Ab", "F#", "B", "Gb", "D" };
char *keyNote = "Gb";
char **foundNote = idealGenericLSearch(&keyNote, notes, 5, sizeof(char *), myStrCmp);
if (foundNote) {
printf("found the note: %s\n", *foundNote);
} else {
printf("did not find note\n");
}我无法理解的是,如果我去掉了(char**)转换和取消引用,为什么我的比较函数仍然同样工作。如果我像这样写cmpfn:
int myStrCmp(void *vp1, void *vp2) {
char *s1 = vp1;
char *s2 = vp2;
return strcmp(s1, s2);
}还能用。当lsearch将elemAddr传递给这个比较函数时,它应该是一个指向char*的指针,在这种情况下,在比较函数中,我将传递strcmp char**。
发布于 2016-01-30 08:32:09
你的问题很有趣!人们可能会预料到一些未定义的行为,甚至是崩溃。这确实是偶然的,但其原因如下:
在测试中使用字符串文字:
char *notes[] = { "Ab", "F#", "B", "Gb", "D" };
char *keyNote = "Gb";您的编译器很可能共享字符串文本,因此notes[3]中的指针具有与keyNote相同的值。
在使用线性搜索时,您将执行strcmp,不是对字符串,而是对它们的地址。地址可能包含一个空字节,如果您的体系结构是小endian,那么地址中的重要非空字节将首先出现。有了这些机会,对于所有其他条目来说,strcmp((char*)notes[3], (char*)&keyNote)确实是0和非0。
您可以通过测试以下内容来验证这一理论:
char *notes[] = { "Ab", "F#", "B", "Gb", "D" };
char *keyNote = strdup("Gb");如果keyNote中有一个不同的指针,一般搜索就会失败。
发布于 2016-01-30 08:28:27
这就是为什么第二个版本的myStrCmp“工作”。第一个版本是您想要的,它将按预期对字符串进行比较。另一方面,第二个版本是将保存字符串地址的指针视为字符串本身。因此,它将指针逐字节地进行比较,就好像它们是字符串一样。如果指针是不同的,那么它很可能会比较为不相等(除非两个指针在它们不同之前包含零字节)。但是如果指针是相同的,那么在遇到不同字节之前,如果在指针中或在指针之后遇到零字节,那么它们就有可能比较相等。
那么,为什么两个"Gb"指针是相同的呢?因为编译器识别它们是相同的字符串,并为两个引用分配一个字符串。
不用说,这是一个非常不明确的行为,因此,分析为什么它有时工作是纯粹的学术。
https://stackoverflow.com/questions/35099513
复制相似问题