Berk Sahin
Berk Sahin

Reputation: 11

C allocating dynamic memory in a function - same results

I tryed to create a multi-dimensional array and I wrote a function but when I check my matrices, I've realized my pointers's values are the same but their addresses are diffrent. Why :)

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

int **matrix(int a,int b){
    int i;
    int **x;
    x = (int**)malloc(a * sizeof(int*));
    for (i = 0; i < a; i++) {
        x[i] = (int*)malloc(b * sizeof(int));
    }
    return x;
}

int main()
{
    int **m1, **m2;
    m1=matrix(3,3);
    m2=matrix(3,3);
    printf("Values: %d %d\n",m1[1][1],m2[1][1]);
    printf("Addresses: %d %d",&m1[1][1],&m2[1][1]);
    return 0;
}

Upvotes: 0

Views: 117

Answers (2)

Elias Van Ootegem
Elias Van Ootegem

Reputation: 76395

Memory-leak-looming!
First off, you have a possible memory-leaking program here. You are allocating memory for 2 matrices, but at no point to you free the allocated memory. You should. All memory allocated on the heap is your responsibility, it is your job to see to it that that memory is free'ed once you're done with it. Possibly implement a function like:

void free_matrix(int **matrix, int len)
{
    if (matrix == NULL) return;//don't try and free NULL pointers
    while(len--) free(matrix[len]);
    free(matrix);
}

to be called in your main function after you've printed out what needed printing out:

free_matrix(m1, 3);
m1 = NULL;//setting unused pointers to NULL is a good habit
free_matrix(m1,3);//won't cause problems
free_matrix(m2, 3);
free_matrix(m2, 1);//ERROR!

You also fail to check if and see if the malloc call actually was successful. If there isn't enough memory available, malloc returns null, and you should handle this. At the very least do:

some_ptr = malloc(sizeof(*some_ptr));
if (some_ptr == NULL) exit(EXIT_FAILURE);//macro expands to 1

Anyway, I've written this codepad that tries to free and reassign the same matrix over and over, until the values in memory are different. As it turns out, on codepad at least, they're alwasy the same.
I'm currently browsing linux kernel code, and the web, to see if there is a reason for this. Perhaps Linux wipes the heap memory when the kernel is idling, or perhaps it's a codepad thing... either way, stay tuned for updates :)

Basically, malloc doesn't initialize the memory it allocates. What the OS does with free'd memory is up to the OS. I've tried the code below on my 64bit linux system, which compiled fine using

gcc -std=c99 -Wall src.c -o temp

And it shows that the matrices do contain different values, but were, in my case mostly 0. Anyway, here's the code:

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

void **matrix(int a,int b)
{
    int i;
    unsigned int **x;
    x = malloc(a * sizeof(*x));
    if (x == NULL) exit(EXIT_FAILURE);
    for (i = 0; i < a; i++)
    {
        x[i] = malloc(b * sizeof(*(x[i])));
        if (x[i] == NULL) exit(EXIT_FAILURE);
    }
    return (void **)x;
}

void free_matrix(void ***m, int l)
{
    if (*m == NULL) return;
    while(l--) free((*m)[l]);
    free(*m);
*m = NULL;
}

int main( void )
{
    unsigned int **m1, **m2, c=0;
    m1 = (unsigned int **) matrix(3,3);
    m2 = (unsigned int **) matrix(3,3);
    printf("%lu <> %lu\n", sizeof(m1[1][1]), sizeof(m1));//4 <> 4 -> 32 bit, 4 <> 8 -> 64
    while(*(m1[1]+1) == *(m2[1]+1) && c < 101)
    {
        ++c;
        free_matrix((void ***) &m1,3);
        m1 = (unsigned int **) matrix(3,3);
    }
    if (c == 101)
    {
        for(c=0;c<3;++c) printf("%u %u %u\n%u %u %u\n\n",*(m1[c]), *(m1[c]+1), *(m1[c]+2),*(m2[c]), *(m2[c]+1), *(m2[c]+2));
    }
    else
    {
        printf("Different vals after %d tries\n", c);
    }
    printf("Values: %u %u %c\n",m1[1][1],m2[1][1], (unsigned char) m1[1][1]);
    printf("Addresses: %p %p\n",(void *) (m1[1]+1), (void *) (m2[1]+1));
    free_matrix((void ***)&m1, 3);
    free_matrix((void ***)&m2,3);
    return 0;
}

And an example of the output I got is here:

4  8
12546112 0 0
0 0 0

12546144 0 0
0 0 0

0 0 0
0 0 0

Values: 0 0
Addresses: 0xbf7054 0xbf70d4

Anyway, I hope this, and the rest of my answer clears a thing or two up for you.

To get the actual addresses you'll have to write:

printf("Addresses: %p, %p\n", (void *) &m1[1][1], (void *)&m1);

As opposed to:

printf("Addresses: %d %d",&m1[1][1],&m2[1][1]);

Because m1[1][1] isn't a pointer! m1 is a pointer to a pointer to an int, so m[1] is a pointer to an int, and m1[1][1] is an int, not a pointer.

Oh, and casting the return value of malloc is not done. It hides possible errors, and malloc will return a compatible pointer type or NULL anyway.

But why are their addresses not the same? well simple: you're allocating 2 separate blocks of heap memory. You're not allocating the same memory twice (that would be impossible).
You're attempting to print out the address of those values that are stored in 2 separate locations in the heap.

It's like building 2 houses that are exactly the same in every way, only you build them in a different city. Their addresses will be unique.

The fact that the values are the same is a coincidence. malloc does not change the contents of the memory, so if the blocks of memory happened to be set to 0 since last they were used, then you'll happen to get zero initialized memory, but you can't be sure this will always be the case... The question you should be asking is not why, but why not or what are the odds

Upvotes: 0

Tanmay Patil
Tanmay Patil

Reputation: 7057

In case of m1[1][1], you are printing values in the array. They are not pointer values. Since you have not initialized them to any value, they can be anything. In your case, they are turning up to be same
&m1[1][1] is a pointer though. Since you are allocating memory twice, they have different values. (Different addresses for array)

Upvotes: 1

Related Questions