如何使用lfind

时间:2013-08-06 13:30:07

标签: c arrays pointers

我使用lfind代码:

int StringPtrCompare(const void *ptr1, const void *ptr2)
{
   return strcmp(*(char(*)[])ptr1, *(char**)ptr2);
}

void Unique()
{
    char*  array[1000] = {0};
    char   buffer[200] = {0};
    size_t count       = 0;
    FILE*  fp          = fopen("text", "r");

    if (fp == NULL)
    { 
        error(1, 0, "Couldn't open text for reading");
    }

    while (count < 1000 && fscanf(fp, "%199s", buffer) == 1)
    {
        if (!lfind(buffer, array, &count, sizeof(char*), StringPtrCompare))
        {
            array[count++] = strdup(buffer);
        }
    }

    fclose(fp);

    for (int i = 0; i < count; i++)
    {
        printf("%s\n", array[i]);
        free(array[i]);
    }
}

这很有效,但最初我得到的是细分错误,相反,在StrPtrCompare中,我用<{p}}替换了strcmp中第一个参数的强制转换。

*(char**)ptr1 

从概念上讲,我不明白为什么会这样。 不是

(char(*)[]) equivalent to (char**)? 

另外,我发现如果我在while循环语句中用buffer替换&buffer,该函数仍然有效。

任何人都可以向我解释这两个奇怪的事情吗?

4 个答案:

答案 0 :(得分:4)

&bufferbuffer将具有相同的值。数组的名称充当指向其第一个元素的指针,这就是为什么两者都相同。

现在,如果我们谈论您的第二个问题(char(*)[]) equivalent to (char**)?

(char(*)[])不是函数指针。它是指向字符数组的指针。 数组和指针不相同.Array可能会衰减为指针。

请查看here

答案 1 :(得分:1)

char(*)[]是指向数组的指针,而char**是指向指针的指针。

不,这些不等同,例如,如果您有char (*arr)[10],此处arr只能分配给相同大小和类型的数组。此外,如果希望指针指向数组,则必须传递不需要执行的数组的地址。

请考虑以下用法:

char arr[10];

char brr[10];

char (*crr)[10] = &arr; /* note the address-of operator, just passing 'arr' will incense the compiler */

crr = &brr; /* again reassigning but to an array of valid type */

将此与char**

进行对比
char *twod_arr[5];

char *twod_brr[4];

char** drr = twod_arr; /* legal, doesn't care about size of array */

drr = twod_brr; /* different array size, still doesn't matter */

答案 2 :(得分:1)

ptr1实际代表的是提供给lfind()的值,它是数组buffer的衰减指针值。

您投射ptr1的内容是指向char数组的指针。取消引用,该表达式生成一个char数组。表达式中的数组衰减到等于其第一个元素的地址的值。这对您有用,因为&bufferbuffer具有相同的指针值(尽管它们具有不同的类型)。最后,strcmp()的第一个参数的结果与传递给lfind()的结果相同,即buffer的衰减指针值。

当您将ptr1转换为(char **)时,这是指向char的指针。引用会产生指向char的指针。但是,由于ptr1()实际上具有数组buffer的衰减指针值,因此此取消引用的结果会导致strcmp()sizeof(char *)字节buffer视为指向char的指针。

在任何一种情况下,您都取消引用了一个指针,该指针的类型与实际位于该地址的对象不兼容,从而导致未定义的行为。在一个案例中,它碰巧解决了,在另一个案例中,它崩溃了。

您可以将ptr1视为实际类型,指向char的指针:

int StringPtrCompare(const void *ptr1, const void *ptr2) {
   return strcmp((const char *)ptr1, *(char**)ptr2);
}

答案 3 :(得分:1)

修复代码

您的代码将错误类型的内容传递给lfind。如果key参数是指向某个类型T的指针,则base参数必须是指向T数组的指针。当您将buffer作为key传递时,则bufferchar的数组,会自动转换为指向char的指针。因此,Tchar。因此base必须是char的数组。但是,您的base是指向char的指针数组,因此类型错误。

要解决此问题,请在定义Unique后在buffer中添加此代码:

char *BufferPointer = buffer;

然后,要拨打lfind,请使用:

if (!lfind(&BufferPointer, &array, &count, sizeof(char*), StringPtrCompare))

通过此调用,第一个参数是指向char指针的指针。因此,类型T是指向char的指针。这匹配&array,它是指向char指针数组的指针。

然后,在StringPtrCompare中,参数ptr1ptr2将各自具有指向T的类型指针。由于T是指向char的指针,{{1}的类型}和ptr1是指向ptr2指针的指针。 (我暂时忽略了char限定符。)然后你可以这样调用const

strcmp

指向数组的指针与指针的指针

指向数组的指针(如int StringPtrCompare(const void *ptr1, const void *ptr2) { return strcmp(* (char **) ptr1, * (char **) ptr2); } )与指针指针(例如char (*)[])不同。如果char **是指向数组的指针,则在p指向的位置必须有一个元素数组:元素的数据必须位于该位置。

相反,如果p是指向指针的指针,则在p指向的位置必须有一个指针:该位置的字节必须包含指针的值

数组与数组地址的对比

p的类型为buffer时,它是char [200]的数组。在表达式中使用数组时,它将转换为指向其第一个元素的指针,除非它是charsizeof_Alignof的操作数,或者是使用的字符串文字初始化一个数组。当您将&传递给buffer时,这些例外都不适用,因此lfind会转换为其第一个buffer的地址。

传递char时,此表达式是数组的地址。数组的地址与其第一个元素的地址具有相同的值,但具有不同的类型。但是,当您将&bufferbuffer传递给&buffer时,它会转换为lfind,因为void *被声明为采用该类型的参数。因此,lfindbuffer的类型之间的差异将丢失,并且仅传递该值。由于它们具有相同的值,因此没有区别。