expected 'double **' but argument is of type 'double (*)[2]'

I encountered this strange behavior in C.

This code gives me the compile warning:

expected 'double **' but argument is of type 'double (*)[2]'

What is the problem? An array of doubles is a pointer to double, right?

BTW, if I send the array itself, the assignment doesn't affect the values and I don't know why.

#include <stdio.h>

void set1(double **x)
{
    (*x)[0] = (*x)[1] =1.0;
}

int main()
{
    double x[2];
    set1(&x);
    printf("%d\n%d\n",x[0],x[1]);
}

4 answers

  • answered 2017-08-12 09:37 Filip Kočica

    You have to pass pointer to array instead of pointer to pointer.

    #include <stdio.h>
    
    void set1(double (*x)[2])
    {
        (*x)[0] = (*x)[1] =1.0;
    }
    
    int main()
    {
        double x[2];
        set1(&x);
        printf("%f\n%f\n",x[0],x[1]);
    }
    

    Output

    1.000000
    1.000000
    

    Specifier %d expects int, change it to %lf.


    Or simplify your code like this

    #include <stdio.h>
    
    void set1(double x[2])
    {
        x[0] = x[1] = 1.0;
    }
    
    int main()
    {
        double x[2];
        set1(x);
        printf("%f\n%f\n", x[0], x[1]);
    }
    

  • answered 2017-08-12 09:37 Johan Boulé

    You can simplify the code like this :

    #include <stdio.h>
    
    void set1(double x[2])
    {
        x[0] = x[1] = 1.0;
    }
    
    int main(void)
    {
        double x[2];
        set1(x);
        printf("%f\n%f\n", x[0], x[1]);
    }
    

  • answered 2017-08-12 09:37 Debanik Dawn

    Instead of sending &x you should only send x in the function. x indicates the address of the first data in the array, and hence the starting address of the array itself. What you should do is:

    void set1(double *x)
    {
        x[0] = x[1] =1.0;
    }
    
    int main()
    {
        double x[2];
        set1(x);
        printf("%d\n%d\n",x[0],x[1]);
    }
    

    You're problem arises because you set the type of the argument as a pointer to a pointer to a double value but sent a pointer to an array of double values of length 2 instead.

  • answered 2017-08-12 09:37 Vlad from Moscow

    For starters according to the C Standard the function main without parameters shall be declared like

    int main( void )
    

    To output objects of type double you should use at least the conversion specifier %f instead of %d. Otherwise the function printf has undefined behavior.

    Now about pointers.

    If you have an object of type T where T is some type specifier sequence as for example

    T x;
    

    then a pointer to the object will have type T *

    So let's write your program using this abstract type T.

    #include <stdio.h>
    
    void set1( T *x )
    {
        //...
    }
    
    
    int main(void) 
    {
        T x;
    
        set1( &x ) ;
    
        // ...
    
        return 0;
    }
    

    The program will not compile because the type T till now is unknown. But what is the type T for the original program?

    It can be defined the following way

    typedef double T[2];
    

    Now if to add this typedef to the program then it will compile.

    #include <stdio.h>
    
    typedef double T[2];
    
    void set1( T *x )
    {
        //...
    }
    
    
    int main(void) 
    {
        T x;
    
        set1( &x ) ;
    
        // ...
    
        return 0;
    }
    

    So what is the type of the function parameter if to use the expression &x as its argument?

    Its type is double ( *x )[2]. It is not the same as double ** and there is no implicit conversion between these two types of pointers. That is pointers of these types are incompatible.

    Returning to your original program in this case it will look like

    #include <stdio.h>
    
    void set1( double ( *x )[2] )
    {
        (*x)[0] = (*x)[1] = 1.0;
    }
    
    
    int main(void) 
    {
        double x[2];
    
        set1( &x ) ;
    
        printf( "%f\n%f\n", x[0] , x[1] );
    
        return 0;
    }
    

    If you want that the function parameter indeed had type double ** then the function argument has to be specified as it is shown in the program below

    #include <stdio.h>
    
    void set1( double **x )
    {
        (*x)[0] = (*x)[1] = 1.0;
    }
    
    
    int main(void) 
    {
        double x[2];
        double *p = x;
    
        set1( &p ) ;
    
        printf( "%f\n%f\n", x[0] , x[1] );
    
        return 0;
    }
    

    In this program the pointer p of the type double * points to the first element of the array and the address of the pointer of the type double ** is passed to the function.

    However to change the elements of the array it is enough to declare the parameter as having the type double * because in this case the elements of the array are already passed indirectly by using a pointer.

    #include <stdio.h>
    
    void set1( double *x )
    {
        x[0] = x[1] = 1.0;
    }
    
    int main(void) 
    {
        double x[2];
    
        set1( x ) ;
    
        printf( "%f\n%f\n", x[0] , x[1] );
    
        return 0;
    }