在C和C ++中将双指针传递给函数的区别

时间:2019-06-04 19:06:44

标签: c warnings

在parseFunc()中,如果我通过传递&tIpArray调用loadFunc(),则在使用C作为编译器时(在onlinegdb.com中)它可以正常编译,但在更高版本的C编译器(gcc-bin / 4.9)中抱怨如下。 4 / gcc)。

工作中的错误类似于在onlinegdb中将语言用作C ++进行编译时看到的错误。有人可以告诉我为什么4.9.4 gcc C编译器不喜欢&以及正确的处理方式吗?

/******************************************************************************

Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby, 
C#, VB, Perl, Swift, Prolog, Javascript, Pascal, HTML, CSS, JS
Code, Compile, Run and Debug online from anywhere in world.

*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>

typedef struct _MyStruct
{
    char string[72];
}MyStruct;

int loadFunc(MyStruct** ipData, int counter)
{
    MyStruct **currentVal = ipData;

    MyStruct *ipPtr = NULL;

    printf("%p\n", currentVal);

    for(int i=0; i<counter; i++)
    {
        ipPtr = currentVal[i];
        printf("Line-%d - %s - %p\n", i+1, ipPtr->string, ipPtr);
    }
}

int parseFunc()
{
        MyStruct*   tIPArray[3];

        for(int i=0; i< 3; i++)
        {
            tIPArray[i] = 0;
            tIPArray[i] = (MyStruct*) calloc(1, sizeof(MyStruct));
            snprintf(tIPArray[i]->string, 72, "Test-String-%d", i+101);         
        }        

        for(int i=0; i<3; i++)
        {
            printf("Line-%d %p-%p- %s\n", i+1, &tIPArray[i], tIPArray[i], tIPArray[i]->string);
        }

        // call the load/ print loadFunc
        loadFunc(&tIPArray, 3);
}

int main()
{
    printf("Hello World\n");
    parseFunc();
    return 0;
}
  

以下是我上班时遇到的错误

error: passing argument 1 of 'loadFunc' from incompatible pointer type [-Werror]
   loadFunc(&tIPArray, 3);
note: expected 'struct MyStruct **' but argument is of type 'struct MyStruct * (*)[(sizetype)((int)((short unsigned int)getMaxAddressObjects() / 4u))]'
 int loadFunc(MyStruct **ipData, int counter)

在onlinegdb.com中将其构建为C ++文件时出现以下错误

main.cpp: In function ‘int parseFunc()’:
main.cpp:49:38: error: cannot convert ‘MyStruct * (*)[3] {aka MyStruct * (*)[3]}’ to ‘MyStruct ** {aka MyStruct **}’ for argument ‘1’ to ‘int loadFunc(MyStruct **, int)’
     loadFunc(&tIPArray, 3);

2 个答案:

答案 0 :(得分:2)

此声明...

        MyStruct*   tIPArray[3];

tIPArray声明为3 MyStruct *的数组。因此,&tIPArray是指向这样的数组的指针,其类型为MyStruct *(*)[3],正如错误消息所指出的那样。此类型与函数参数的预期类型MyStruct **不同。

您可以改为将显式指针传递给第一个元素...

        loadFunc(&tIPArray[0], 3);

...,但是省略&会更加惯用,因为将数组普通转换为指针(数组的“衰减”)会生成正确类型和值的指针:

        loadFunc(tIPArray, 3);

答案 1 :(得分:2)

如果使用typedef MyStruct* StrPtr;,也许会更清楚。然后您的示例变为:

void foo(StrPtr* bar);

StrPtr array[4];

首先,让我们看看这个电话:

foo(array);

数组的类型为StrPtr[4],而不是StrPtr*。理想情况下,它将调用foo(StrPtr bar[4]),但是没有这样的功能。下一个最佳匹配是数组可以衰减为指向其元素= StrPtr*的指针,幸运的是有foo(StrPtr* bar)函数使调用有效。

现在,该表达式的类型是什么?

&array;

好吧,数组也是StrPtr[4]类型的,因此它必须是指向该类型= StrPtr(*)[4]的指针。与函数指针相同的“怪异”语法。

最后,请拨打此电话:

foo(&array);

我们现在知道这想调用foo(StrPtr(*bar)[4]),并且再次没有这样的功能。那么编译器能做什么? &array不是数组,它是一个指针,指针不能衰减到任何东西。嗯,现在呢?好吧,在C中,无论类型如何,任何指针都可以传递给另一个指针。取消引用此类指针是另一回事。因此,此呼叫有效,并且由于没有其他候选者而呼叫foo(StrPtr* bar)。成功?不,任何体面的编译器都应对此进行警告,甚至最好像使用-Wincompatible-pointer-types一样将这些警告转换为错误,甚至禁止使用-Werror禁止所有警告。

因此,可以得出的结论是正确的呼叫是foo(array);