Search code examples
cpointerspass-by-referencecomplex.h

Passing pointer to complex double in C (using complex.h)


I am trying to run a function, int testfn below, which should assign a complex number to the pointer (to a complex number), double _Complex *foo below, that it is fed. The minimal (non-working) example .c file is test.c below.

When I call testfn through main, instead of returning the assigned value 1.0 + 0.5*I, it returns 0.0 + 0.0*I. I do not understand why, or how to fix it.

test.c

#include <stdio.h>      
#include <stdlib.h>
#include <math.h>
#include <complex.h>

int testfn(double _Complex *foo) {
    double _Complex foobar = 1.0 + 0.5*I;
    foo = &foobar;
    printf("foobar = %.8f + I %.8f \n",creal(foobar),cimag(foobar));
    printf("*foo = %.8f + I %.8f \n",creal(*foo),cimag(*foo));
    return 0;
}

int main() {
    double _Complex toot;
    testfn(&toot);
    printf("toot = %.8f + I %.8f \n",creal(toot),cimag(toot));
    return 0;
}

compile and run with

cc -o test test.c -L. -lm -Wall
./test

terminal output gives wrong answer

foobar = 1.00000000 + I 0.50000000 
*foo = 1.00000000 + I 0.50000000 
toot = 0.00000000 + I 0.00000000 

Notice that the actual answer for toot should be toot = 1.00000000 + I 0.50000000.


On the other hand, this array case works

Here, in test2.c, I am feeding double _Complex (*foo)[3], i.e. a three-dimensional array of pointers to complex numbers (is that right?) to int testarrayfn, and then assigning foo to be a specific 2x3 matrix of complex numbers inside testarrayfn.

When I call testarrayfn from main using double _Complex toot[2][3]; and testarrayfn(toot);, I do get the right answer. I am not sure why this is done right (I just googled and played around a lot with arrays, and passing array arguments).

test2.c

#include <stdio.h>      
#include <stdlib.h>
#include <math.h>
#include <complex.h>

int testarrayfn(double _Complex (*foo)[3]) {
    double _Complex foobar;
    int i,j;
    for (i=0;i<2;i++) {
        for (j=0;j<3;j++) {
            foobar = 1.*(i+1) + 0.5*(j+1)*I ;
            foo[i][j] = foobar;
            printf("[%d][%d]: foobar = %.8f + I %.8f \n",i,j,creal(foobar),cimag(foobar));
            printf("foo[%d][%d] = %.8f + I %.8f \n",i,j,creal(foo[i][j]),cimag(foo[i][j]));
            }
        }
    return 0;
}

int main() {
    double _Complex toot[2][3];
    testarrayfn(toot);
    int i,j;
    for (i=0;i<2;i++) {
        for (j=0;j<3;j++) {
            printf("toot[%d][%d] = %.8f + I %.8f \n",i,j,creal(toot[i][j]),cimag(toot[i][j]));
            }
        }
    return 0;
}

compile and run with

cc -o test2 test2.c -L. -lm -Wall
./test2

terminal output gives expected answer

[0][0]: foobar = 1.00000000 + I 0.50000000 
foo[0][0] = 1.00000000 + I 0.50000000 
[0][1]: foobar = 1.00000000 + I 1.00000000 
foo[0][1] = 1.00000000 + I 1.00000000 
[0][2]: foobar = 1.00000000 + I 1.50000000 
foo[0][2] = 1.00000000 + I 1.50000000 
[1][0]: foobar = 2.00000000 + I 0.50000000 
foo[1][0] = 2.00000000 + I 0.50000000 
[1][1]: foobar = 2.00000000 + I 1.00000000 
foo[1][1] = 2.00000000 + I 1.00000000 
[1][2]: foobar = 2.00000000 + I 1.50000000 
foo[1][2] = 2.00000000 + I 1.50000000 
toot[0][0] = 1.00000000 + I 0.50000000 
toot[0][1] = 1.00000000 + I 1.00000000 
toot[0][2] = 1.00000000 + I 1.50000000 
toot[1][0] = 2.00000000 + I 0.50000000 
toot[1][1] = 2.00000000 + I 1.00000000 
toot[1][2] = 2.00000000 + I 1.50000000 

Additional questions about complex.h

I could not find the answers to the following questions anywhere:

  1. Can one use double complex foo and double _Complex foo interchangeably, both inside a function, and an argument?
  2. Can one use double complex *foo and double _Complex *foo interchangeably, both inside a function, and an argument?
  3. Can one use double complex (*foo)[3] and double _Complex (*foo)[3] interchangeably, both inside a function, and an argument?
  4. More generally, is there any difference between double complex, double _Complex, and complex double?

Solution

  • Test1

    Two problems.

    1. foo is a local variable. When you assign it it only will be valid in the function scope.
    2. foobar is a local variable and it cannot be accessed after the function return (as it stops to exist)

    You need to make foobar exist after the function return and pass the reference to the pointer.

    int testfn(double _Complex **foo) {
        static double _Complex foobar = 1.0 + 0.5*I;
        *foo = &foobar;
        printf("foobar = %.8f + I %.8f \n",creal(foobar),cimag(foobar));
        printf("*foo = %.8f + I %.8f \n",creal(**foo),cimag(**foo));
        return 0;
    }
    
    int main() {
        double _Complex *toot;
        testfn(&toot);
        printf("toot = %.8f + I %.8f \n",creal(*toot),cimag(*toot));
        return 0;
    }
    

    or assign the underlying object with the value of the foobar (not reference)

    int testfn(double _Complex *foo) {
        double _Complex foobar = 1.0 + 0.5*I;
        *foo = foobar;
        printf("foobar = %.8f + I %.8f \n",creal(foobar),cimag(foobar));
        printf("*foo = %.8f + I %.8f \n",creal(*foo),cimag(*foo));
        return 0;
    }
    
    int main() {
        double _Complex toot;
        testfn(&toot);
        printf("toot = %.8f + I %.8f \n",creal(toot),cimag(toot));
        return 0;
    }
    

    Test2 works because you assign the values to the referenced object, not trying to change the pointer to the array.

    you can write the foo[i][j] = foobar; as *(*(foo + i) + j) = foobar; and it is identical as my second example (you can treat toot as single element array)

    _Complex is an actual C keyword from C99 (or GCC extension before C99). complex is a simple definition expanding to _Complex. It is done this way as many old programs use its own complex type