简体   繁体   English

C-释放指针数组时会发生什么?

[英]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. 我目前正在用C编程,并且正在创建一个指针数组。 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. 假设指针数组是数组A。然后创建另一个指针B数组,然后将数组A的元素放入数组B。然后释放数组A。

What will happen to the element in array B? 数组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? 由于数组A已被释放,它将不再有效,还是由于实际指针在内存中仍然有效,它将仍然有效?

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]? 现在,array_b [0]会发生什么?

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. 那么b也将无效。

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. 那么b仍然有效。

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. 因此,通常在释放指针后将指针设置为NULL是一个好主意。

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: 因此,我不久前才刚刚学到一些关于free()的知识,所以很遗憾地说我对此了解不多,但这是我所知道的一点:

To return dynamically allocated memory to the system, you use the free() function. 要将动态分配的内存返回给系统,请使用free()函数。 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. 因此,我相信B将仍然有效,而不再引用A。 Java periodically collects dynamically allocated memory that is no longer referenced and it goes in the 'garbage.' Java会定期收集不再分配的动态分配的内存,并将其放入“垃圾”中。 C doesn't do that, which is why we use free(). C不这样做,这就是为什么我们使用free()的原因。 Hope that helps a bit. 希望有点帮助。 I'm still learning myself. 我还在学习自己。 Good question :) 好问题 :)

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. C将数组解释为基本元素的地址,因此根据您释放数组的方式,您可能根本没有释放该元素。

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). 但是,假设您确实释放了数组的所有元素,则数组B中的指针仍将在那里(它仍将指向内存中的同一位置)。 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. 但是绝对不安全。

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的指针(12或24个字节),

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[], 现在,您将先前定义的变量a,b,c的地址存储到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, 例如,根据声明a,b,c的位置,这完全是无害的,还是非常危险的,

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, 声明和分配array_b []的空间,并保留单个内存位置类似于声明和数组一个指向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_a [0]的内容(从上面开始是变量a,&a的地址)放入内容,并且与将&a存储在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, 释放array_a是无害的,因为array_a中没有存储任何可能“泄漏”的内容,并且不会影响array_b [0],因为其中包含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. 现在您已经分配了100 + 1个存储位置,这仍然可以。

Then suppose you allocated array_b will enough space to hold all of array_a[], 然后假设您分配的array_b将有足够的空间来容纳所有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_b [ndx]指向的内存,总共100 + 1个内存位置泄漏,

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]. 由于您仅复制了array_a的地址,而不复制了array_a [0..99]的地址,因此上述方法将泄漏array_b,array_b [0..99]指向的所有内存以及array_a [0..99]的所有内存。

Here is how you would copy the memory allocated at array_a[0..99], 这是复制在array_a [0..99]中分配的内存的方法,

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM