0

I am practicing the use of malloc function. I have declared two complex matrices: H and result. All the elements of H are 1.1+0i, and all the elements of result are 0+2.2i as original values. I have copied H to result, and then printed them. The result shows that some elements are just 0+0i, which is apparently not the case. Could you help me to figure out what is wrong in the code?

/*
 * This C code is for simulation for printing complex channel matrix by using struct 
 *
 * let matrix H be 8 by 4
 * 2017.05.24
 *
 */

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

struct str_dcomplex
{
    double re;
    double im;
};

typedef struct str_dcomplex dcomplex;

int main() {

    void print_matrix(char* desc, int m, int n, dcomplex a[m][n]) {
        int i, j;
        printf("\n%s\n",desc);
        for(i = 0; i < m; i++) {
            for(j = 0; j < n; j++) {
                printf("(%5.1f,%5.1f)",a[i][j].re, a[i][j].im);
            }
        printf("\n");
        }
    }

    void matrix_copy(int r, int c, dcomplex source[r][c], dcomplex dest[r][c]) {
        int i, j;
        for(i = 0; i < r; i++) {
            for(j = 0; j < c; j++) {
                dest[i][j].re = source[i][j].re;
                dest[i][j].im = source[i][j].im;
            }
        }
    }

    int p,q;
    int i,j;

    // memory allocation for H
    dcomplex **H;
    H = (dcomplex**)malloc(sizeof(dcomplex*)*8);
    for(p = 0; p < 8; p++) {
        H[p] = (dcomplex*)malloc(sizeof(dcomplex)*4);
    }

//  dcomplex(*H)[4] = dcomplex(*)[4]malloc(sizeof(dcomplex)*8*4);

    for(p = 0; p < 8; p++) {
        for(q = 0; q < 4; q++) {
            H[p][q].re = 1.1;
            H[p][q].im = 0.0;
        }
    }

    dcomplex** result;
    result = (dcomplex**)malloc(sizeof(dcomplex*)*8);
    for(p = 0; p < 8; p++) {
        result[p] = (dcomplex*)malloc(sizeof(dcomplex)*4);
    }

    for(p = 0; p < 8; p++) {
        for(q = 0; q < 4; q++) {
            result[p][q].re = 0.0;
            result[p][q].im = 2.2;
        }
    }


    // declare and assign variables
    //dcomplex H[8][4] = {{{1,2},{3,4},{5,6},{7,8}},{{1,2},{3,4},{5,6},{7,8}},{{1,2},{3,4},{5,6},{7,8}},{{1,2},{3,4},{5,6},{7,8}},{{1,2},{3,4},{5,6},{7,8}},{{1,2},{3,4},{5,6},{7,8}},{{1,2},{3,4},{5,6},{7,8}},{{1,2},{3,4},{5,6},{7,8}}};
    //dcomplex result[8][4] = {{{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}};

    // print H and result
    print_matrix("original H is: \n",8,4,H);
    print_matrix("original result is: \n",8,4,result);

    // copy H to result
    matrix_copy(8,4,H,result);

    // print H and result
    print_matrix("new H is: \n",8,4,H);
    print_matrix("new result is: \n",8,4,result);

    int count = 0;
    for(i = 0; i < 8; i++) {
        for(j = 0; j < 4; j++){
            if((H[i][j].re == result[i][j].re) && (H[i][j].im == result[i][j].im))
                count++;
        }
    }
    printf("\n%d\n\n",count);

    //printf("\nmatrix copy completed...\n\n");
    //printf("\nSize of dcomplex is: %d\n\n",sizeof(dcomplex));

    // free the memory
    for(i = 0; i < 8; i++) {
        free(H[i]);
    }
    free(H);

    for(i = 0; i < 8; i++) {
        free(result[i]);
    }
    free(result);

    return 0;
}

Screenshot of execution result: execution result screenshot

Update: I changed the arguments of print_matrix and matrix_copy, dcomplex a[m][n] to dcomplex** a[m][n], dcomplex source[r][c] to dcomplex** source[r][c] and dest... and a[i][j].re to a[i][j]->re etc, etc. It still doesn't work... Cannot figure out the bugs.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
MiaT
  • 11
  • 2
  • 6
  • 4
    According to the C Standard you may not define a function inside another function. Though maybe some compilers have their own language extentions it is better to write C-compliant programs. – Vlad from Moscow May 29 '17 at 23:36
  • I can't understand your question. You ask us what's wrong, but don't describe any problem. What makes you think something's wrong? – David Schwartz May 29 '17 at 23:38
  • `void matrix_copy(int r, int c, dcomplex source[r][c], dcomplex dest[r][c])` : `source` and `dest` are not `dcomplex**` – BLUEPIXY May 29 '17 at 23:38
  • Hey Vlad, thanks for your explanation. Would you please tell more details about this issue? I don't quite get you. – MiaT May 29 '17 at 23:39
  • @labixiaowanzi Vlad is referring to you defining functions `print_matrix` and `matrix_copy` in the function `main`. That's not allowed in C. – kamoroso94 May 29 '17 at 23:55
  • `dcomplex a[m][n]` to `dcomplex **a` – BLUEPIXY May 29 '17 at 23:57
  • Hi all, I changed the arguments of print_matrix and matrix_copy, dcomplex a[m][n] to dcomplex** a[m][n], dcomplex source[r][c] to dcomplex** source[r][c] and dest... and a[i][j].re to a[i][j]->re etc,etc. Still it doesn't work... cannot figure out the bugs.. – MiaT May 29 '17 at 23:58
  • like [this](http://ideone.com/ojNiSk) – BLUEPIXY May 30 '17 at 00:09
  • You have to decide whether you want a jagged array (separate allocation per row), or a contiguous array (entire array in one memory allocation). The function can only accept one or the other but you are mixing two techniques at the moment. – M.M May 30 '17 at 06:57
  • Also, pay attention to your compiler messages. The code you have posted would produce a large number of message. Don't ignore them and don't even bother running your program until you have fixed all the issues raised in the messages. – M.M May 30 '17 at 06:59

3 Answers3

1

You're using malloc properly.

dcomplex **H;
H = (dcomplex**)malloc(sizeof(dcomplex*)*8);
for(p = 0; p < 8; p++) {
    H[p] = (dcomplex*)malloc(sizeof(dcomplex)*4);
}

I assume these are the lines in question? You're going to have to debug the rest of your code to fix your problem.

Sam Pagenkopf
  • 258
  • 1
  • 5
  • 4
    This seems like more of a comment than an answer. That said, more idiomatic C does _not_ cast the result of `malloc()`, and uses identifiers instead of explicit types in `sizeof` expressions: `dcomplex **H = malloc(sizeof *H * 8);` and `H[p] = malloc(sizeof **H * 4)`. This reduces clutter, is less error-prone to write, and easier to maintain when types change. – ad absurdum May 30 '17 at 00:48
  • I was just copy-pasting his code, there's many more style suggestions I'd make than that but it didn't feel relevant. – Sam Pagenkopf May 30 '17 at 02:37
  • 3
    Sam, you had less than 20 reputation, so I don't think you can comment yet (soon). But do understand, when you answer questions on SO, you step into the role of teacher. You want to make every effort to install correct coding practices when doing so. See: [**Do I cast the result of malloc?**](http://stackoverflow.com/q/605845/995714) for thorough explanation. (keep that link handy, it comes up very often... and Welcome to SO) – David C. Rankin May 30 '17 at 05:29
  • Thanks, guess I just need to acclimate. – Sam Pagenkopf May 30 '17 at 23:05
1

You're not using anything from either <math.h> or <complex.h> — you're using your own dcomplex type. Those headers may as well not be present.

The nested function notation is an abomination — GCC allows it, but it shouldn't, and you should not use the notation.

When the functions are unnested (I decline to find out what happens when they are nested), the compiler complains bitterly and justly:

cx19.c: In function ‘main’:
cx19.c:76:42: error: passing argument 4 of ‘print_matrix’ from incompatible pointer type [-Werror=incompatible-pointer-types]
     print_matrix("original H is: \n",8,4,H);
                                          ^
cx19.c:15:6: note: expected ‘dcomplex (*)[(sizetype)(n)]’ but argument is of type ‘dcomplex ** {aka struct str_dcomplex **}’
 void print_matrix(char* desc, int m, int n, dcomplex a[m][n]) {
      ^~~~~~~~~~~~
cx19.c:77:47: error: passing argument 4 of ‘print_matrix’ from incompatible pointer type [-Werror=incompatible-pointer-types]
     print_matrix("original result is: \n",8,4,result);
                                               ^~~~~~

You're passing a dcomplex ** and pretending it is a dcomplex[m][n] type. I'm sorry to inform you that the compiler is correct and your code is wrong.

If you want to pass variable-length 2D arrays, you'll have to allocate variable-length 2D arrays. If you want to pass pointers to pointers, you'll have to revise the functions.

Using a dynamically allocated array of pointers

Changing the functions is easy; simply change the type of the relevant arguments. Note that there are no other necessary changes to the functions than the change in the function signature.

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

struct str_dcomplex
{
    double re;
    double im;
};

typedef struct str_dcomplex dcomplex;

static
void print_matrix(char* desc, int m, int n, dcomplex **a) {
    int i, j;
    printf("\n%s\n",desc);
    for(i = 0; i < m; i++) {
        for(j = 0; j < n; j++) {
            printf("(%5.1f,%5.1f)",a[i][j].re, a[i][j].im);
        }
        putchar('\n');
    }
}

static
void matrix_copy(int r, int c, dcomplex **source, dcomplex **dest) {
    int i, j;
    for(i = 0; i < r; i++) {
        for(j = 0; j < c; j++) {
            dest[i][j].re = source[i][j].re;
            dest[i][j].im = source[i][j].im;
        }
    }
}

int main(void) {
    int p,q;
    int i,j;

    // memory allocation for H
    dcomplex **H;
    H = (dcomplex**)malloc(sizeof(dcomplex*)*8);
    for(p = 0; p < 8; p++) {
        H[p] = (dcomplex*)malloc(sizeof(dcomplex)*4);
    }

    for(p = 0; p < 8; p++) {
        for(q = 0; q < 4; q++) {
            H[p][q].re = 1.1;
            H[p][q].im = 0.0;
        }
    }

    dcomplex** result;
    result = (dcomplex**)malloc(sizeof(dcomplex*)*8);
    for(p = 0; p < 8; p++) {
        result[p] = (dcomplex*)malloc(sizeof(dcomplex)*4);
    }

    for(p = 0; p < 8; p++) {
        for(q = 0; q < 4; q++) {
            result[p][q].re = 0.0;
            result[p][q].im = 2.2;
        }
    }

    // print H and result
    print_matrix("original H is: \n",8,4,H);
    print_matrix("original result is: \n",8,4,result);

    // copy H to result
    matrix_copy(8,4,H,result);

    // print H and result
    print_matrix("new H is: \n",8,4,H);
    print_matrix("new result is: \n",8,4,result);

    int count = 0;
    for(i = 0; i < 8; i++) {
        for(j = 0; j < 4; j++){
            if((H[i][j].re == result[i][j].re) && (H[i][j].im == result[i][j].im))
                count++;
        }
    }
    printf("\n%d\n\n",count);

    // free the memory
    for(i = 0; i < 8; i++) {
        free(H[i]);
    }
    free(H);

    for(i = 0; i < 8; i++) {
        free(result[i]);
    }
    free(result);

    return 0;
}

The output from that is:

original H is: 

(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)

original result is: 

(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)
(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)
(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)
(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)
(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)
(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)
(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)
(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)(  0.0,  2.2)

new H is: 

(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)

new result is: 

(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)
(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)(  1.1,  0.0)

32

Using dynamically allocated variable-length arrays

It's also perfectly feasible to dynamically allocate the variable-length arrays, and pass those to the functions. This leads to code like this:

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

struct str_dcomplex
{
    double re;
    double im;
};

typedef struct str_dcomplex dcomplex;

static void print_matrix(char *desc, int m, int n, dcomplex a[m][n])
{
    int i, j;
    printf("\n%s\n", desc);
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
            printf("(%5.1f,%5.1f)", a[i][j].re, a[i][j].im);
        putchar('\n');
    }
}

static void matrix_copy(int r, int c, dcomplex source[r][c], dcomplex dest[r][c])
{
    int i, j;
    for (i = 0; i < r; i++)
    {
        for (j = 0; j < c; j++)
            dest[i][j] = source[i][j];
    }
}

int main(void)
{
    int p, q;
    int i, j;

    // memory allocation for H
    dcomplex(*H)[4] = malloc(sizeof(H[0]) * 8);
    assert(H != 0);  // Sloppy!

    for (p = 0; p < 8; p++)
    {
        for (q = 0; q < 4; q++)
            H[p][q] = (dcomplex){ .re = 1.1, .im = 0.0 };
    }

    dcomplex (*result)[4] = malloc(sizeof(result[0]) * 8);
    assert(result != 0);  // Sloppy!

    for (p = 0; p < 8; p++)
    {
        for (q = 0; q < 4; q++)
            result[p][q] = (dcomplex){ .re = 0.0, .im = 2.2 };
    }

    // print H and result
    print_matrix("original H is:", 8, 4, H);
    print_matrix("original result is:", 8, 4, result);

    // copy H to result
    matrix_copy(8, 4, H, result);

    // print H and result
    print_matrix("new H is:", 8, 4, H);
    print_matrix("new result is:", 8, 4, result);

    int count = 0;
    for (i = 0; i < 8; i++)
    {
        for (j = 0; j < 4; j++)
        {
            if ((H[i][j].re == result[i][j].re) && (H[i][j].im == result[i][j].im))
                count++;
        }
    }
    printf("\n%d\n\n", count);

    // free the memory
    free(H);
    free(result);

    return 0;
}

The code also uses some compound literals with designated initializers, and loosely error checks the memory allocation. Using assert() for error checking isn't sensible in production code; this isn't production code and it suffices.

The output is very similar — there isn't a blank line between the matrix description and the matrix data.

Using regular variable-length arrays

#include <stdio.h>

struct str_dcomplex
{
    double re;
    double im;
};

typedef struct str_dcomplex dcomplex;

static void print_matrix(char *desc, int m, int n, dcomplex a[m][n])
{
    printf("\n%s\n", desc);
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
            printf("(%5.1f,%5.1f)", a[i][j].re, a[i][j].im);
        putchar('\n');
    }
}

static void matrix_copy(int r, int c, dcomplex source[r][c], dcomplex dest[r][c])
{
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
            dest[i][j] = source[i][j];
    }
}

static void matrix_init(int r, int c, dcomplex target[r][c], dcomplex value)
{
    for (int p = 0; p < r; p++)
    {
        for (int q = 0; q < c; q++)
            target[p][q] = value;
    }
}

int main(void)
{
    int r = 8;
    int c = 4;

    dcomplex H[r][c];
    matrix_init(r, c, H, (dcomplex){ .re = 1.1, .im = 0.0 });

    dcomplex result[r][c];
    matrix_init(r, c, result, (dcomplex){ .re = 0.0, .im = 2.2 });

    // print H and result
    print_matrix("original H is:", r, c, H);
    print_matrix("original result is:", r, c, result);

    // copy H to result
    matrix_copy(r, c, H, result);

    // print H and result
    print_matrix("new H is:", r, c, H);
    print_matrix("new result is:", r, c, result);

    int count = 0;
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            if ((H[i][j].re == result[i][j].re) && (H[i][j].im == result[i][j].im))
                count++;
        }
    }
    printf("\n%d\n\n", count);

    return 0;
}

The change to using variable length arrays is simple, and means we no longer need to use <stdlib.h>. I created the matrix_init() function to initialize the arrays — it cuts down on repetition in the main() function. If you use array sizes determined at run-time, it is important to do sanity checks on the array size; there is a limit on how much space is available on the stack. However, the size of these arrays (8 * 4 * 2 * sizeof(double), which is usually 512 bytes) isn't going to stress any modern desktop machine.

The change to using classic fixed size arrays is trivial. The changes to set the values of r and c is likewise basically trivial.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Hey Jonathan, thank you for your impressive answers. Three different ways are really helpful. I just wonder if there are any Pros and Cons to choose which one of these three? thx... – MiaT Jun 06 '17 at 18:37
  • Regular variable-length arrays are allocated on the stack, and the stack is of limited size (usually 8 MiB on Unix-like systems, either 1 or 2 MiB — I forget which — on Windows systems). So, if you're using regular variable-length arrays, you need to keep the amount of space you've got allocated in mind to avoid stack overflows. Choosing between the dynamically allocated options — variable-length arrays and arrays of pointers — is less clear cut. Both allow you to use the regular subscript notation. The arrays of pointers will work with old (C90) compilers. Arrays of pointers use more space. – Jonathan Leffler Jun 06 '17 at 19:05
-2

I'm not sure if this is the problem but passing dcomplex dest to void matrix_copy(int r, int c, dcomplex source[r][c], dcomplex dest[r][c]) only passes the value. You should change matrix_copy(8,4,H,result) to matrix_copy(8,4,H, &result) and void matrix_copy(int r, int c, dcomplex source[r][c], dcomplex dest[r][c]) to void matrix_copy(int r, int c, dcomplex **source, dcomplex ***dest)

The Cat
  • 11
  • 1
  • 6