user2985902
user2985902

Reputation: 1

C - What happens to an array of pointers when the array is freed?

I am currently programming in C, and I am creating an array of pointers. These pointers contained in the array will last for the duration of the entire program.

Let's say the array of pointers is array A. I then create another array of pointers B, and I put an element of array A into array B. Then, I free array A.

What will happen to the element in array B? Will it no longer be valid since array A has been freed, or will it still be valid, since the actual pointer is still valid in memory?

Thanks

Here's an example of what my code will look like--

int a = 1;
int b = 2;
int c = 3;

int **array_a = (int **) malloc (sizeof (int *) * 3);
array_a[0] = &a;
array_a[1] = &b;
array_a[2] = &c;

int **array_b = (int **) malloc (sizeof (int *) * 1);
array_b[0] = array_a[0];
free(array_a);

Now, what happens to array_b[0]?

Upvotes: 0

Views: 713

Answers (5)

ChuckCottrill
ChuckCottrill

Reputation: 4444

These three lines declare memory for three integers, and initialize the integers. Should you do this outside of a function, you can happily take the address of these variables and store them in your array.

int a = 1;
int b = 2;
int c = 3;

However, should the above three variables be declared in a function (on the stack) and you take the address of them, and store those addresses somewhere, you have created a (potential) dangling pointer problem.

This line allocates enough memory to hold three pointers to int (12 or 24 bytes),

int **array_a = (int **) malloc (sizeof (int *) * 3);

Now you store the address of the earlier defined variables a,b,c into the array_a[],

array_a[0] = &a;
array_a[1] = &b;
array_a[2] = &c;

Which is either perfectly harmless, or very dangerous, depending upon where a,b,c were declared, for example,

int** youfun()
{
    int a = 1;
    int b = 2;
    int c = 3;
    int **array_a = (int **) malloc (sizeof (int *) * 3);
    array_a[0] = &a;
    array_a[1] = &b;
    array_a[2] = &c;
    return(array_a); //very bad!
}

int a = 1;
int b = 2;
int c = 3;
int** mefun()
{
    int **array_a = (int **) malloc (sizeof (int *) * 3);
    array_a[0] = &a;
    array_a[1] = &b;
    array_a[2] = &c;
    return(array_a); //safe, but strange
}

Declaring and allocating space for array_b[], and reserving a single memory location is similar to declaring and array of one pointer to int,

int **array_b = (int **) malloc (sizeof (int *) * 1);

The following assignment places the contents of array_a[0] (which is the address of variable a, &a, from above), and is only as dangerous/innocuous as having the &a stored in array_a[0],

array_b[0] = array_a[0];

Freeing the array_a is harmless, because nothing is stored in array_a which might 'leak', and does not affect array_b[0], as that contains the address of a, &a,

free(array_a);

Suppose you did the following instead,

int **array_a = (int **) malloc (sizeof (int *) * 100);
int ndx;
for(ndx=0; ndx<100; ++ndx)
    array_a[ndx] = malloc( sizeof(int) );

You would now have allocated 100+1 memory locations, which is still fine.

Then suppose you allocated array_b will enough space to hold all of array_a[],

int **array_b = (int **) malloc (sizeof (int *) * 100);
int ndx;
for(ndx=0; ndx<100; ++ndx)
    array_b[ndx] = malloc( sizeof(int) );

This would leak memory (pointed at by array_b), plus the memory pointed at by each array_b[ndx], for a total of 100+1 memory location leaks,

array_b = array_a; //discarded memory references at array_b[0..99], and array_b

Now suppose you did both of these,

array_b = array_a; //you just discarded the memory references at array_b[0..99] and array_b
free(array_a); //you just discarded array_a[0..99]

The above would leak all memory pointed to by array_b, array_b[0..99] and all memory at array_a[0..99], as you only copied array_a's address, not the addresses at array_a[0..99].

Here is how you would copy the memory allocated at array_a[0..99],

for(ndx=0; ndx<100; ++ndx)
    array_b[ndx] = array_a[ndx];

Upvotes: -1

user2985903
user2985903

Reputation:

So I just learned a little bit about free() not too long ago, so I'm sorry to say I don't know too much about it yet, but here's the little that I do know:

To return dynamically allocated memory to the system, you use the free() function. My professor used this kind of example:

struct listNode *Bob;
Bob = &any instance of listNode;
free(Bob);

So I believe B will still remain valid while A is no longer referenced. Java periodically collects dynamically allocated memory that is no longer referenced and it goes in the 'garbage.' C doesn't do that, which is why we use free(). Hope that helps a bit. I'm still learning myself. Good question :)

Upvotes: 0

gongzhitaao
gongzhitaao

Reputation: 6682

The pointers itself doesn't change, it still points where it pointed. The only thing is that the location it points to might be allocated to some other program. You could still write and read the location with undefined behaviour. Check this code:

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

int main()
{
    int *a = (int *)malloc(3 * sizeof(int));
    a[0] = 1, a[1] = 2, a[2] = 3;
    free(a);
    // a = NULL // if you add this, the following will crash.
    printf("%d\n", a[0]);
    printf("%d\n", a[1]);
    printf("%d\n", a[2]);
    return 0;
}

If you are lucky, you could still get the correct result. But it's just luck.

So it's usually good idea to set the pointer to NULL after being freed.

Upvotes: 1

Cam
Cam

Reputation: 66

C interprets an array as the address of the base element, so depending on how you have freed the array you may not have freed the element at all.

However, assuming you did free all the elements of the array, your pointer in array B will still be there (it will still point to the same location in memory). However, you really don't know what is at that location because you already freed the memory there. You may still get the original data stored there, or it may have been overwritten. Definitely not safe to use it, though.

Upvotes: -1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726499

If you do this

int *a = malloc(10 * sizeof(int));
for (int i = 0 ; i != 10 ; i++) {
    a[i] = 2*i+1;
}
int *b = a;
free(a);

then b would be invalid as well.

If you do this, however

int *a = malloc(10 * sizeof(int));
for (int i = 0 ; i != 10 ; i++) {
    a[i] = 2*i+1;
}
int *b = malloc(10 * sizeof(int));
memcpy(b, a, 10 * sizeof(int));
free(a);

then b remains valid.

Upvotes: 2

Related Questions