c - 如何在C中重新分配指向较小数组的指针?
问题描述
有没有办法在 C 中重新分配指向数组的指针,使其指向更小尺寸的数组?例如,如果我有一个ptr
最初指向s
大小为 3 的数组的指针,并且还存在一个s1
大小为 2 的数组,我是否可以重新分配ptr
以使其指向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;
}
但是当我在 VIsual Studio 中运行它时,我收到一个错误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
当我打印出ptr
调用后的值时changePtr
。为什么是这样?
解决方案
编辑 1
对于你原来的问题:
简短回答:是的,您可以在 C 中重新分配指向较小数组的指针。
长答案:简短的答案具有误导性。数组也是 C 中的简单指针。为了更好地理解这个概念,您可能需要阅读这个线程,特别是看看这个答案。
问题是您尝试在stack
.
每当您创建一个局部变量 à laint 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
另一方面,创建动态内存(例如 via )发生在heap
内存中,需要由程序员进行管理,即允许分配(malloc()
)和取消分配(free()
)内存,并且必须非常小心。
因此,在您的程序中,当它到达这一行时free(ptr);
,断言失败,因为目标内存地址不符合要求 -> IsValidHeapPointer
: Noptr
不是有效的堆指针,因为它保存了该s
变量的堆栈地址。:)
编辑 2
当我在调用 changePtr 后打印出 ptr 的值时,我得到像 -1456815990147....1 这样的垃圾值。为什么是这样?
ptr
这是因为,您首先释放了in的内存changePtr(ptr)
,也就是说,它的内容ptr
被写入了一些“垃圾”值。
然后在这里分配新内存并将其分配给ptr
:
ptr = (double *) malloc(sizeof(double) * 2);
在此之后,您通过ptr
(ie ptr[i] = 12
) 所做的更改对之前ptr
持有的地址没有影响。所以,只需删除free(ptr)
上面的行,你就不需要它们了。
编辑 3
那么
ptr
现在只包含 2 个值,对吗?在我删除你提到的那一行,然后打印出 ptr 中的值之后,它显示 ptr[0] 和 ptr[1] 的正确值,然后是 ptr[2] 的垃圾值。
正确的。ptr[2]
之前已被释放,因此除非您为该地址分配新值,否则它将仍然是垃圾。释放堆内存后也要小心。您不应使用指针访问内存或为其分配新值。在你调用它之后考虑你的指针“void” free
。
当我尝试用 printf("%d", sizeof(ptr)) 打印它的大小时,它显示为 8,而 printf("%d", sizeof(ptr)/sizeof(ptr[0]) 显示为 1。
ptr
是一个指针。sizeof(ptr)
返回8
字节,这是系统中指针所保存的地址大小。所以,这不是数组的大小......此外,在changePtr(ptr)
运行时确定指针的大小(指向数组并作为引用传递给函数 - 就像你做的那样)在编程上是不可能的,你必须明确如果要执行一些循环操作,请将数组大小传递给函数。
推荐阅读
- linux-kernel - 静默丢弃对 mmap 区域的写入
- c# - Asp.Net MVC C# 更新/编辑用户模型状态无效
- deserialization - Azure 服务总线中转消息反序列化
- python - 如何使用 argparse parse_args 将参数解析为 python 中的字符串?
- assembly - 如何快速将寄存器中的立即数转换为字符以存储在字符串中
- c++ - 如何在unix中获取当前工作目录中最大的文件?
- javascript - 告诉页面通过锚点聚焦元素的事实上的方式是什么?
- react-native - 拥有图像@2x @3x 与只有一张高分辨率图像
- r - 如何根据一列中的值更新多行重复?
- entity-framework-core - EF Core 无法确定“ICollection”类型的导航属性“Colour.ColourGroups”表示的关系
'