1

I have piece of code like this and I want to alloc memory for two dimmensional struct array.

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

struct complex
{
    int re;
    int im;
};

int main ()
{
    int r = 5; //rows
    int c = 6; //cols

    struct complex (*wsk)[c];
    wsk = (struct complex(*)[c])malloc(sizeof(struct complex)*r*c);

    /* ... */
}

I'm not sure about the malloc() part, is it correct?

Haris
  • 12,120
  • 6
  • 43
  • 70
The Cataylyst
  • 45
  • 1
  • 5
  • Where did the `k` variable come from? also is there a reason you set wsk as a pointer? I dont know exactly what your doing obviously but from what i can tell you dont need it as a pointer. Last thing is you dont need to cast malloc in c. – JackV Aug 23 '15 at 21:40
  • Any reason for not using `struct complex sk[5][6]` and avoid the `malloc`? – Bo Persson Aug 23 '15 at 21:51
  • @JackV There was a typo, k should be c. – The Cataylyst Aug 23 '15 at 21:54
  • @BoPersson Well I use pointers since I was taught to to this on my classes. And I have to use malloc when I have such command in excercise – The Cataylyst Aug 23 '15 at 21:57
  • 1
    `struct complex (*wsk)[c] = calloc(r, sizeof *wsk);` or if you are hell-bent on `malloc`, then `struct complex (*wsk)[c] = malloc(r * sizeof *wsk);` – WhozCraig Aug 23 '15 at 22:19
  • Standard warning: do not cast `void *` as returned by `malloc` & friends in C. C is **not** C++. – too honest for this site Aug 23 '15 at 22:34
  • `wsk = malloc(sizeof *wsk * r);` – chux - Reinstate Monica Aug 24 '15 at 12:00
  • @WhozCraig so i don't have to multiply by cols too? only rows? and use sizeof *wsk instead of sizeof(struct complex)? why? – The Cataylyst Aug 24 '15 at 13:11
  • 1
    These two options for calculating the size are equivalent. When using `malloc`, it's usually preferred to write `number * sizeof *pointer` for "the size of the `struct` the pointer points to, multiplied by their number". This is better, because then you can freely change the type of the `struct` without having to update the argument of `malloc`. However, in your case, the pointer points to an array `complex[c]`, not to a struct - so it's "`r` times the size of the array" vs "`r*c` times the size of the struct". The latter is probably less confusing, while both are correct. – anatolyg Aug 24 '15 at 13:52

3 Answers3

0

There is a typo in these statements

struct complex (*wsk)[k];
                     ^^^
wsk = (struct complex(*)[k])malloc(sizeof(struct complex)*r*c);
                         ^^

I think you mean

struct complex (*wsk)[c];
                     ^^^
wsk = (struct complex(*)[c])malloc(sizeof(struct complex)*r*c);
                         ^^

If so then this code is correct provided that the compiler supports Variable Length Arrays.

int main (){
    int r = 5; //rows
    int c = 6; //cols

    struct complex (*wsk)[c];
    wsk = (struct complex(*)[c])malloc(sizeof(struct complex)*r*c);
...
}

Otherwise you should define c like a preprocessor constant

#define c 6

Or you should dynamically allocte a one dimensional array of pointers and each element of the array in turn should be the address of a dynamically allocated one-dimensional array of objects of the given type.

Take into account that if main does not have parameters then according to the C Standard it must be declared like

int main( void )
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Here's a common way to do it. I find this the best when all rows have the same number of columns, so in most cases. Reasons:

  • malloc is slow. Use as few malloc-s as you can
  • You always need to free wsk and wsk[0]. This is great when you change r and c run-time: you don't have to store old values to free the proper number of rows.

Also, don't forget to check if malloc returned NULL.

struct complex ** wsk = (struct complex **) malloc(r *  sizeof(struct complex*));
wsk[0] = (struct complex *) malloc(r * c * sizeof(struct complex));
int i;
for(i = 1; i < r; ++i)
    wsk[i] = wsk[0] + i * c;

Oh, and why didn't you typedef the struct?

typedef struct complex complex;

Or even simpler, at the declaration:

typedef struct /*complex*/ {
    ...
} complex;

Then you don't have to write struct complex all the time, just complex.

dobragab
  • 69
  • 1
  • 2
  • 7
-1

It's nice to see that someone knows how to define e pointer to an array to allocate a 'real' multidimensional array dynamically (int (*)[]...[]). Normally everybody allocates array of pointers to array... (i.e. int *[]).

But there are errors on sizing. If your scope is to create an array of 5 rows and 6 columns of complex structures the code must be:

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

struct complex
{
    int re;
    int im;
};

int main(int argc, char *argv[])
{
    int r = 5; //rows
    int c = 6; //cols

    struct complex (*wsk)[r][c];

    wsk = malloc(sizeof(struct complex)*r*c);

    for (int i=0; i<r; i++)
        for(int j=0; j<c; j++)
        {
            (*wsk)[i][j].re =     10*i + j;
            (*wsk)[i][j].im = -1*(10*i + j);
        }

    for (int i=0; i<r; i++)
    {
        for(int j=0; j<c; j++)
            printf("r=%+2.2d i=%+2.2d  ", (*wsk)[i][j].re, (*wsk)[i][j].im);
        printf("\n");
    }

    return 0;
}

The output is:

r=+00 i=+00  r=+01 i=-01  r=+02 i=-02  r=+03 i=-03  r=+04 i=-04  r=+05 i=-05
r=+10 i=-10  r=+11 i=-11  r=+12 i=-12  r=+13 i=-13  r=+14 i=-14  r=+15 i=-15
r=+20 i=-20  r=+21 i=-21  r=+22 i=-22  r=+23 i=-23  r=+24 i=-24  r=+25 i=-25
r=+30 i=-30  r=+31 i=-31  r=+32 i=-32  r=+33 i=-33  r=+34 i=-34  r=+35 i=-35
r=+40 i=-40  r=+41 i=-41  r=+42 i=-42  r=+43 i=-43  r=+44 i=-44  r=+45 i=-45
Frankie_C
  • 4,764
  • 1
  • 13
  • 30
  • 1
    It would be **very very nice to know why has been downvoted**! A technically correct answer treated in this way is not a positive thing for an answers site... – Frankie_C Aug 23 '15 at 22:51
  • Maybe it was downvoted because it says "there are errors on sizing", when there are no such errors (IMHO). It then proceeds to restate the OP's original code as the "correct" way, without stating explicitly what the problem was, and how it was fixed. Confusing! – anatolyg Aug 24 '15 at 09:43
  • 1
    @Frankie_C I am sure that the reason for downvoting is that the author was not going to declare a pointer to a whole array and to write everywhere this compound expression (*wsk)[i][j]. He wants to allocate a 2D array as usually arrays are allocated and gets the pointer to the first element of the array. In this case he can just write wsk[i][j]. – Vlad from Moscow Aug 24 '15 at 10:09
  • @Frankie_C The author does not want to allocate an array of 2D arrays. – Vlad from Moscow Aug 24 '15 at 10:15
  • @anatolyg Thanks for clarification. Maybe I was too fast and unclear, it was late here, but declaring the array as a classical array of pointers to an array of strcutures, to access it as a pseudo bidimensional array, requires another allocation for the array of pointers. And the last was missing. – Frankie_C Aug 24 '15 at 13:21
  • @VladfromMoscow Thanks Vlad, First problem here is the language on my side evidently :). I understood that the problem seems to be more aesthetic than functional. But I made a premise in the answer saying that this is a general way to declare multidimensional dynamic arrays having any dimension. The method used has 2 main defects IMHO, hiddens the bidimensional nature of the array making the code less readable, and uses a special case when you have just 2 dimensions, but what for 3,4 and so on? The solution I proposed permits you to deal with arrays of how many dimensions you want. – Frankie_C Aug 24 '15 at 13:43
  • @VladfromMoscow If the title is "C malloc two dimensional struct array (with rows and cols)" why the hell it should mean "not a 2D array"? – Frankie_C Aug 24 '15 at 13:46
  • @Frankie_C I can not agree with you. Consider for example declaration char *s = "Hello"; The string literal has type char[6]. However you do not write char ( * )[6] = "Hello". Such record only confuses readers. Now you always need to write *s everywhere including calls of standard C functions that deal with strings instead of s. For example to copy the string literal pointed to by this pointer to another array you have to write strcpy( t, *s ); Nobody will understand this record. – Vlad from Moscow Aug 24 '15 at 13:49
  • @Frankie_C Arrays are converted to pointers to their first elements with rare exception for example when an array is used in the sizeof operator. So if you have an array like int a[N][M] then using its name in expressions results in converting it to type int ( * )[M]. In this case you can interchangeably use the array and the pointer to its first element as an argument of most functions. – Vlad from Moscow Aug 24 '15 at 13:56
  • @VladfromMoscow Basically I agree with you, but I would prefer the `(*)` notation where it would be better to show the multidimensional nature of the array. – Frankie_C Aug 24 '15 at 14:04
  • @Frankie_C Using a record like int ( * )[M} is enough to show the multidimensional nature of an array. Let's return to the example with string literals. If you will write char *s = "Hello"; then you can use the same pointer that to wriite s = "Hello World";. If you will write char ( *s )[6] = &"Hello"; then you may not write *s = "Hello World"; because the type in the left and right sides are different.. Using a pointer to the first element of an array reflects the dual nature of arrays and pointers. – Vlad from Moscow Aug 24 '15 at 14:13
  • @Frankie_C Consider for example the subscript operator. A record like this s[i] is calculated like *( s + i ). So you may write for example "hello"[0] and 0["Hello"] – Vlad from Moscow Aug 24 '15 at 14:16