5

I have a function that supposed to take 2D array as an argument, my code looks like this --

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

void func(double**, int);

int main()
{
    double m[3][3] = {{1, 1, 1}, {2, 2, 2}, {3, 3, 3}};
    func(m, 3);
}

void func(double **m, int dim)
{
    int i, j ;
    for(i = 0 ; i < dim ; i++)
    {
        for(j = 0 ; j < dim ; j++)
            printf("%0.2f ", m[i][j]);
        printf("\n");
    }
}

Then the compiler says --

test.c: In function ‘main’:
test.c:9:2: warning: passing argument 1 of ‘func’ from incompatible pointer type [enabled by default]
  func(m, 3);
  ^
test.c:4:6: note: expected ‘double **’ but argument is of type ‘double (*)[3]’
 void func(double**, int);
      ^

But when I say --

int main()
{
    int i, j;
    double m[3][3] = {{1, 1, 1}, {2, 2, 2}, {3, 3, 3}};
    double **m1 ;
    m1 = (double**)malloc(sizeof(double*) * 3);
    for(i = 0 ; i < 3 ; i++)
    {
        m1[i] = (double*)malloc(sizeof(double) * 3);
        for(j = 0 ; j < 3 ; j++)
            m1[i][j] = m[i][j] ;
    }
    func(m1, 3);
    for(i = 0 ; i < 3 ; i++) free(m1[i]);
    free(m1);
}

It compiles and runs.

Is there any way I can make func() to take both the statically/dynamically defined 2D array ? I am confused since I am passing the pointer m, why it is not correct for the first case ?

does it mean that I need to write two separate functions for two different types of arguments?

M.M
  • 138,810
  • 21
  • 208
  • 365
ramgorur
  • 2,104
  • 4
  • 26
  • 39
  • 2
    [Don't cast the result of `malloc`](http://stackoverflow.com/q/605845/119527). – Jonathon Reinhart May 28 '15 at 07:31
  • Another duplicate that might explain better: http://stackoverflow.com/q/13952511/119527 – Jonathon Reinhart May 28 '15 at 07:38
  • 1
    The point is, `double m[3][3]` is an array-of-arrays... all 9 `doubles` are contiguous in memory. A `double **` is **not** a 2D array - rather it can be considered an array of *pointers*. Reading an element in the former incurs one dereference, whereas the latter incurs two. – Jonathon Reinhart May 28 '15 at 07:40
  • @OliverC this question has remote similarities with other question but is not a duplicate. – Mohit Jain May 29 '15 at 04:14
  • Your description is misleading. It makes no difference at all whether the array was statically or dynamically allocated. It's not clear whether you're asking "How do I have a function accept both a 2-D array and an array of pointers", or "How can I dynamically allocate a 2-D array" - although since you accepted an answer describing the latter I guess that is what you intended. – M.M Jun 01 '15 at 08:08

1 Answers1

5

Your dynamic allocation for 2d array is not correct. Use it as:

double (*m1)[3] = malloc(sizeof(double[3][3]));

And then it will work.

Moreover change the function prototype to:

void func(double m[][3], int dim)

Another way is to use a 1-D array of size w * h instead of 2-D array.

Working example


From comment of @TheParamagneticCroissant c99 onwards, you can also VLA's and make both your dimensions variable. (You'll need to allocate the 2D array properly though)

Change function signature to:

void func(int dim, double[dim][dim]);  /* Second arg is VLA whose dimension is first arg */
/* dim argument must come before the array argument */

Working example

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • @JonathonReinhart The type of `m1` is different and so is the layout. – Mohit Jain May 28 '15 at 07:33
  • but I can't use a variable inside the declaration, like `malloc(sizeof(int[len][len]));` right ? what if I do not want to specify `3` ? – ramgorur May 28 '15 at 07:36
  • 2
    If you want to make both dimensions variable, use the later advice (1-D array of size `w*h`) or make one dimension constant. – Mohit Jain May 28 '15 at 07:43
  • 1
    @ramgorur You *can* use a variable in that position, [unless the compiler defines `__STDC_NO_VLA__`](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=195), in which case you can detect this and error out at compile-time (which you should do, because don't put up with that from your compiler). – Alex Celeste May 28 '15 at 07:45
  • @MohitJain in C99 and later, variable-length arrays (and pointers to them) **can** be passed to functions. No dimension needs to be constant. – The Paramagnetic Croissant May 29 '15 at 06:00
  • @TheParamagneticCroissant Thanks, details added. – Mohit Jain May 29 '15 at 06:19