0

I am very new to use C, I wrote the code bellow to create a 2d int array, can anyone help to generic it to other types, like float, double ... ? or other function can be use directly?

int** alloc_arrays(int m,int n) {
    int **MN = (int **)malloc(sizeof(int *)*m);
    if(MN == NULL) {
        exit(1);
    }
    for(int i=0; i<m;i++) {
        MN[i] = (int *)malloc(sizeof(int)* n);
        if(MN[i] == NULL){
            exit(1);
        }
        memset(MN[i],0, n);
    }  
    return MN;  
}

void free_arrays(int **arrays,int m){
    if(arrays==NULL){
        exit(1);
    }
    for(int i=0;i< m; i++){
        if(arrays[i] ==NULL){
            exit(1);
        }
        free(arrays[i]);
    }    
    free(arrays);
}   
Vality
  • 6,577
  • 3
  • 27
  • 48
lessisawesome
  • 1,313
  • 1
  • 12
  • 14

3 Answers3

2

Not pretty, but it works:

#include <stdlib.h>

#define ALLOC_ARRAYS(ptr, M, N) do { \
    size_t m = (M), n = (N); \
    if ( NULL == ((ptr) = malloc(m * sizeof *(ptr))) ) exit(1); \
    for (size_t i = 0; i < m; ++i) \
         if ( NULL == ((ptr)[i] = calloc(n, sizeof **(ptr))) ) exit(1); \
    } while (0)

Sample usage:

int main()
{
     double **ptr;
     ALLOC_ARRAYS(ptr, 5, 10);        
}

Note: calloc (or equivalently, memset to 0) only generates well-defined values for integral types (or if you know your system is using IEEE754 for doubles). It might be better to explicitly initialize each element to an initializer that you pass to the macro; or have a different macro for initializing.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • this code work well, but i don't know why added do...while here? this code still working when remove do while. – lessisawesome Aug 21 '14 at 15:43
  • @lessisawesome it means you can use `ALLOC_ARRAYS` in any context where you can use a function call; e.g. `if ( foo ) ALLOC_ARRAYS(ptr, 5, 10); else other_func();` – M.M Aug 21 '14 at 19:31
1

You can use a macro like this:

#define MAKE_ARRAY(A, N, M) A = calloc(sizeof(**A) * N, M)

And you would use it like this:

int N = 4;
int M = 10;

int (*x)[M];
double (*y)[M];

MAKE_ARRAY(x, N, M);
MAKE_ARRAY(y, N, M);

/* ... */

free(y);
free(x);
jxh
  • 69,070
  • 8
  • 110
  • 193
  • `M` is redundant here since it is part of the type information, you could have the macro be `#define MAKE_ARRAY(A,N) ( (A) = calloc( N, sizeof *(A) ) )`. Incidentally this will work with non-array types too. – M.M Aug 21 '14 at 08:25
  • @Matt x,y are at block scope, what it's means? – lessisawesome Aug 21 '14 at 15:46
  • This code illustrates how it is used in combination with the variable length array feature of C99. This only works in block scope (inside a function). – jxh Aug 21 '14 at 16:24
  • @jxh I'm not sure what you mean, `M` is redundant whether or not it is a VLA so it only serves to introduce a way to allocate the wrong amount of memory if you don't specify the matching value for `M` – M.M Aug 21 '14 at 19:33
  • @MattMcNabb: Originally, I had the macro cast the return value of `calloc()` before assigning to the variable, and this was to verify the type of the array pointer `A`. Before publishing the post, I took out the cast. – jxh Aug 21 '14 at 22:05
0

Your not far off. You can fix/improve your code by improving the allocation.

MN[i] = (int *)malloc(sizeof(int)* n);

should be:

MN[i] = malloc(sizeof(**MN) * n);  /* instead of malloc(sizeof(int)); */

using the variable itself, rather than (int) makes the allocation generic and reduces chance of mistake. malloc knows what you are allocating.

if you want to allocate and set the contents to 0 at the same time, use calloc. You could change the same line to:

MN[i] = calloc (n, sizeof(**MN));

Note: do not cast malloc or calloc. It only increases the chance of mistake.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85