3

Consider following codes:

#include <stdio.h>
#include <malloc.h>

void allocateMatrix(int **m, int l, int c)
{
    int i;

    m = (int**) malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        m[i] = (int*) malloc( sizeof(int) * c );
}

int main()
{
    int **m;
    int l = 10, c = 10;
    allocateMatrix(m, l, c);
    m[0][0] = 9;
    printf("%d", m[0][0]);

    return 0;
}

The code above will generate an memory allocation error and will crash.

But the code below will work correctly, the question is: WHY?

#include <stdio.h>
#include <malloc.h>

int** allocateMatrix(int l, int c)
{
    int i;

    int **m = (int**) malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        m[i] = (int*) malloc( sizeof(int) * c );
    return m;
}

int main()
{
    int **m;
    int l = 10, c = 10;
    m = allocateMatrix(l, c);
    m[0][0] = 9;
    printf("%d", m[0][0]);

    return 0;
}

I cannot see why the first code crashes, since I'm just passing the pointer-to-pointer m (the variable that holds the memory first memory address of the matrix) as an argument. I see no difference between the codes (in practice). I would appreciate any clear explanation.

Thank you, Rafael Andreatta

rafaame
  • 822
  • 2
  • 12
  • 22

4 Answers4

7

In the first example you don't initialize m. You merely change your copy of it. So, put otherwise, the caller will never see what you did to m.

In the second example you allocate memory and then return a pointer to it. Which is valid.

You might be able to fix your first example like this (untested but should work):

void allocateMatrix(int ***m, int l, int c)
{
    int i;

    *m = malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        (*m)[i] = malloc( sizeof(int) * c );
}


/* ... */

allocateMatrix(&m, l, c);

EDIT

Took me a while but I found it. As usual the C FAQ has something to say about this.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • Perhaps this answer could use a comment about scopes and why the first example doesn't work – cthom06 Jun 13 '11 at 12:33
  • Let me see if I get it. When I pass variables as arguments to functions, inside the function I'm CREATING new variables (the arguments), and COPYING THE VALUES from the variables passed as arguments to the variables created for arguments. Am I right? So, in this case, if I'm not initializing the variable m before passing it, the int** m inside the allocateMemory will have a random value (the junk value that int** m in the main function got when created). The unique thing that I don't understand is WHY it will work if I initialize int **m before passing it as argument... Thanks – rafaame Jun 13 '11 at 12:49
  • @rafaame I think you got the first part right. For the second part, if you initialize `m` before calling the function, after the function is done, it will contain the address of valid memory, instead of "the junk value". – cnicutar Jun 13 '11 at 13:02
1

The function allocateMatrix receives a copy of the passed variable m, not the variable the you are passing from the main. Thus, in the first example m is not initialized and when you try to access is you get a segmentation fault.

Ottavio Campana
  • 4,088
  • 5
  • 31
  • 58
1

This is a tricky one, and happens because with:

void allocateMatrix(int **m, int l, int c);

you're one level of indirection out. If you pass a pointer, the value that points to is in effect passed by reference. However, the actual pointer value is copied onto the stack, i.e. is still pass by value. So your allocation function has a local copy of the heap address, but this is never re-assigned to m in the preceding scope.

To fix this, you can use either the second case, or this:

void allocateMatrix(int ***m, int l, int c)
{
    int i;
    *m = (int**) malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        (*m)[i] = (int*) malloc( sizeof(int) * c );
}

and pass with &m.

I also would like to point out in C, you probably are better off not casting the result of malloc, although you are required to in C++. See this answer.

Community
  • 1
  • 1
0

Because in first example variable m (in main) is not changed. To change it, you must pass it as reference (in C++) or by pointer (in plain C).

frp
  • 1,119
  • 1
  • 10
  • 30