如何在C中将指针重新分配给较小的数组?

时间:2019-05-21 23:17:36

标签: c arrays pointers dynamic heap-memory

是否有一种方法可以在C中重新分配指向数组的指针,使其指向更小的数组?例如,如果我有一个指针ulimit -a最初指向大小为3的数组ptr,并且还存在一个大小为2的数组s,可以重新分配{{1} },使其指向s1,从而指向较小的数组?

我尝试了以下代码:

ptr

但是,当我在VIsual Studio中运行它时,我在s处收到一条错误,提示void changePtr(double* ptr); int main() { double *ptr; ptr = (double*)malloc(sizeof(double)*3); double s[3]={1,2,3}; ptr=s; changePtr(ptr); return 0; } void changePtr(double* ptr) { double s1[2]={4,5}; free(ptr); ptr = (double*)malloc(sizeof(double)*2); ptr=s1; }

这是为什么?

编辑

新代码是:

free(ptr)

但是当我调用Debug Assertion failed! Expression: _CrtIsValidHeapPointer(block)后打印出void changePtr(double* ptr); int main() { double *ptr; ptr = (double*)malloc(sizeof(double)*3); double *s; s = (double*)malloc(sizeof(double)*3); s[0]=1; s[1]=2; s[0]=3; for (int i=0; i<3; i++){ ptr[i]=s[i]; } changePtr(ptr); for (int i=0; i<2; i++){ printf("%f\t", ptr[i]); } free(ptr); free(s); return 0; } void changePtr(double* ptr) { free(ptr); double *s1; s1 = (double*)malloc(sizeof(double)*2); s1[0]=11; s1[1]=12; ptr = (double*)malloc(sizeof(double)*2); for (int i=0; i<2; i++){ ptr[i]=s1[i]; } } 的值时,却得到了-1456815990147....1这样的垃圾值。为什么会这样?

2 个答案:

答案 0 :(得分:2)

编辑1

您的原始问题:

简短的回答:是的,您可以在C中将指针重新分配给较小的数组。

长答案:短答案具有误导性。数组也只是C语言中的指针。为了更好地理解该概念,您可能需要阅读this thread,尤其是看看this answer


问题是您尝试在stack上取消分配内存。

无论何时创建局部变量àla int a = 5,它都会被压入堆栈,也就是说,该变量将在堆栈上分配内存,并且在函数调用(main())结束之后,取消分配-所有这些都会自动发生!

在您的情况下,会发生以下情况:

// memory is allocated automatically on stack for the local variable "s"
double s[3]={1,2,3};

// assign the stack address of "s" to "ptr"
ptr = s;

// de-allocate the managed stack address of "s", which is NOT allowed!
free(ptr);

创建动态内存,例如另一方面,通过malloc发生在heap内存中,该内存需要由程序员进行管理,即分配(malloc())和取消分配(free() )允许存储,并且必须格外小心。

因此,在您的程序中,当它到达此行free(ptr);时,声明将失败,因为目标内存地址不符合要求-> IsValidHeapPointer:否ptr不是有效的堆指针,因为它在此时保存s变量的堆栈地址。 :)


编辑2

  

当我在调用changePtr之后打印出ptr的值时,得到了像-1456815990147 .... 1这样的垃圾值。为什么会这样?

这是因为,您首先释放了ptrchangePtr(ptr)的内存,也就是说ptr的内容被写入了一些“垃圾”值。

然后在这里分配新的内存,并将其分配给ptr

ptr = (double *) malloc(sizeof(double) * 2); 

此后,您通过ptr(即ptr[i] = 12)所做的更改对ptr持有的先前地址没有影响。因此,只需删除free(ptr)和上面的行,就不需要它们。


编辑3

  

那么ptr现在只包含2个值了吗?在删除您提到的那一行之后,然后打印出ptr中的值之后,它将显示ptr [0]和ptr [1]的正确值,然后显示ptr [2]的垃圾值。

正确。 ptr[2]之前已被释放,因此,除非您为该地址分配新值,否则它将仍然是垃圾。释放堆内存后也要小心。您不应使用指针访问内存或为其分配新值。在调用free之后,将指针视为“ void”。

  

当我尝试使用printf(“%d”,sizeof(ptr))打印它的大小时,它显示为8,而printf(“%d”,sizeof(ptr)/ sizeof(ptr [0])显示为1.

ptr是一个指针。 sizeof(ptr)返回8字节,这是系统中指针所保存的地址大小。因此,它不是数组的大小...此外,在运行时确定指针的大小(指向数组并传递给函数作为引用,就像您执行changePtr(ptr)一样)是{{3 }},如果要执行一些循环操作,则必须将数组大小显式传递给函数。

答案 1 :(得分:1)

好吧,当您这样做

double s[3]={1,2,3};

该内存不受您管理,因此无法释放它。您只有在使用malloc或calloc分配内存(即动态分配的内存)时才能使用free。另外,那里有内存泄漏,因为

ptr=(double*)malloc(sizeof(double)*3); // here you allocate memory 
...
ptr = s; // here you change the pointer address but allocated memory is never freed

一种解决方案是使用for循环将值从s复制到ptr,并在changePtr中执行相同的操作以将值从s1复制到ptr。