Kingkong Jnr
Kingkong Jnr

Reputation: 1158

Difference in passing a double pointer to a function in C and C++

In parseFunc() if I call loadFunc() by passing &tIpArray, it compiles fine when using C as the compile(in onlinegdb.com) but complains as below on a later version of C compiler(gcc-bin/4.9.4/gcc) at work.

Error at work is similar to what I see when I compile when using language as C++ in onlinegdb. Can someone tell me why the 4.9.4 gcc C compiler doesn't like the & and what is the right way to handle this?

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

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;
}

Below is the error I get at work

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)

Below error when building this in onlinegdb.com as C++ file

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);

Upvotes: 0

Views: 196

Answers (2)

Quimby
Quimby

Reputation: 19113

Perhaps it can be clearer if we use typedef MyStruct* StrPtr;. Then your example becomes:

void foo(StrPtr* bar);

StrPtr array[4];

First, let look at this call:

foo(array);

Array is of type StrPtr[4], not StrPtr*. Ideally this would call foo(StrPtr bar[4]) but there's no such function. The next best match is that arrays can decay to pointers to their elements = StrPtr* and luckily there's foo(StrPtr* bar) function so the call is valid.

Now, what is type of this expression?

&array;

Well, again array is of type StrPtr[4] so this must be a pointer to that type = StrPtr(*)[4]. Same "weird" syntax as for function pointers.

At last, take this call:

foo(&array);

We now know that this would like to call foo(StrPtr(*bar)[4]) and again there's no such function. So what can compiler do? &array is not an array, it's a pointer and pointers cannot decay to anything. Hmm, what now? Well, in C any pointer can be passed to another no matter the type. Dereferencing such pointer is another thing. So, this call is valid and calls foo(StrPtr* bar) as there's no other candidate. Success? No, any decent compiler should warn against this, even better turning those warnings into errors using -Wincompatible-pointer-types or even forbid all warnings with -Werror as you did.

So, the take away is that correct call is foo(array);.

Upvotes: 2

John Bollinger
John Bollinger

Reputation: 180201

This declaration ...

        MyStruct*   tIPArray[3];

declares tIPArray as an array of 3 MyStruct *. Therefore, &tIPArray is a pointer to such an array, its type is MyStruct *(*)[3], just as the error message says. This is not the same type as MyStruct **, which is the expected type of the function argument.

You can instead pass an explicit pointer to the first element ...

        loadFunc(&tIPArray[0], 3);

... but it would be more idiomatic to just omit the &, since ordinary conversion of array to pointer ("decay" of the array) produces a pointer of the correct type and value:

        loadFunc(tIPArray, 3);

Upvotes: 2

Related Questions