0

我目前正在用 C 编程,并且正在创建一个指针数组。数组中包含的这些指针将持续整个程序的持续时间。

假设指针数组是数组 A。然后我创建另一个指针数组 B,并将数组 A 的元素放入数组 B。然后,我释放数组 A。

数组 B 中的元素会发生什么?由于数组 A 已被释放,它是否不再有效,或者它仍然有效,因为实际指针在内存中仍然有效?

谢谢

这是我的代码的示例 -

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);

现在,array_b[0] 会发生什么?

4

5 回答 5

2

如果你这样做

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

那么b也将是无效的。

但是,如果您这样做

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);

那么b仍然有效。

于 2013-11-13T03:15:19.737 回答
1

指针本身不会改变,它仍然指向它所指向的位置。唯一的问题是它指向的位置可能被分配给其他程序。您仍然可以使用未定义的行为写入和读取位置。检查此代码:

#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;
}

如果你幸运的话,你仍然可以得到正确的结果。但这只是运气。

因此,NULL在释放后将指针设置为通常是个好主意。

于 2013-11-13T03:25:55.217 回答
0

所以我不久前刚刚了解了一些关于 free() 的知识,所以很抱歉我对它还不太了解,但这里是我所知道的一点:

要将动态分配的内存返回给系统,请使用 free() 函数。我的教授使用了这样的例子:

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

所以我相信 B 在不再引用 A 时仍然有效。Java 会定期收集不再被引用的动态分配的内存并将其放入“垃圾”中。C 不这样做,这就是我们使用 free() 的原因。希望那些对你有帮助。我还在学习自己。好问题 :)

于 2013-11-13T03:30:09.533 回答
-1

这三行声明三个整数的内存,并初始化整数。如果您在函数之外执行此操作,您可以愉快地获取这些变量的地址并将它们存储在您的数组中。

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

但是,如果上述三个变量在一个函数中(在堆栈上)声明并且您获取它们的地址并将这些地址存储在某个地方,那么您已经创建了一个(潜在的)悬空指针问题。

这一行分配了足够的内存来保存三个指向 int 的指针(12 或 24 字节),

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

现在将前面定义的变量 a,b,c 的地址存储到 array_a[] 中,

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

这要么完全无害,要么非常危险,具体取决于声明 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
}

为 array_b[] 声明和分配空间,并保留单个内存位置类似于声明一个指向 int 的指针的数组,

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

以下赋值放置了 array_a[0] 的内容(这是上面变量 a、&a 的地址),并且仅与将 &a 存储在 array_a[0] 中一样危险/无害,

array_b[0] = array_a[0];

释放array_a 是无害的,因为array_a 中没有存储任何可能“泄漏”的内容,并且不会影响array_b [0],因为它包含a 的地址,&a,

free(array_a);

假设您改为执行以下操作,

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

您现在将分配 100+1 个内存位置,这仍然很好。

然后假设您分配的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) );

这会泄漏内存(由 array_b 指向),加上每个 array_b[ndx] 指向的内存,总共有 100+1 个内存位置泄漏,

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

现在假设你做了这两个,

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]

以上将泄漏array_b、array_b[0..99] 指向的所有内存以及array_a[0..99] 处的所有内存,因为您只复制了array_a 的地址,而不是array_a[0..99] 处的地址。

以下是复制在 array_a[0..99] 分配的内存的方法,

for(ndx=0; ndx<100; ++ndx)
    array_b[ndx] = array_a[ndx];
于 2013-11-13T03:54:04.363 回答
-1

C 将数组解释为基本元素的地址,因此根据您释放数组的方式,您可能根本没有释放元素。

但是,假设您确实释放了数组的所有元素,那么您在数组 B 中的指针仍将存在(它仍将指向内存中的同一位置)。但是,你真的不知道那个位置是什么,因为你已经释放了那里的内存。您可能仍会获得存储在那里的原始数据,或者它可能已被覆盖。但是,使用它绝对不安全。

于 2013-11-13T03:16:38.017 回答