我对realloc函数有疑问。应用realloc函数后,是否会更改旧指针的内容? 代码是
main () {
int *a, *b, i;
a = calloc(5, sizeof(int));
for (i = 0; i < 5; i++)
a[i] = 1;
for (i = 0; i < 5; i++)
printf("%d", a[i]);
printf("\n%p\n", a);
b = realloc(a, 200000 * sizeof(int));
if(b == NULL)
printf("error\n");
for (i = 0; i < 5; i++)
printf("%d", a[i]);
printf("\n");
for (i = 0; i < 10; i++)
printf("%d", b[i]);
printf("\n%p %p\n", a, b);
}
输出
11111
0x2558010
00111
1111100000
0x2558010 0x7f29627e6010
指针仍指向同一地址,但内容已更改。
答案 0 :(得分:6)
指针仍指向同一地址,但内容已更改。
这是因为realloc()
可能会首先尝试增加a
指向的块的大小。但是,它可以改为分配一个新块,将数据(或尽可能多的数据)复制到新块,并释放旧块。在调用a
之后,您确实不应该使用b = realloc(a, 200000 * sizeof(int))
,因为realloc
调用可能会将块移动到新位置,而a
指向不再分配的内存。请改用b
。
答案 1 :(得分:4)
realloc
返回的值告诉您它是成功还是失败。
b = realloc(a, 200000 * sizeof(int));
如果失败,则返回空指针,a
仍然指向原始未修改的内存块(当然b
是空指针)。
如果成功,则b
指向(可能是新分配的)内存块,a
的值为不确定。如果它能够将旧块分配到与旧块相同的位置(通过增加或缩小块),那么b
将等于a
- 但是测试它,或者即使是指a
的值,也有未定义的行为。如果必须重新定位块,则realloc
在复制数据后将完成相当于free(a)
的操作。在任何一种情况下,最好将a
设置为NULL
,以避免意外引用其(现在不确定)值。
请注意,即使新大小较小,realloc
也可以重新定位块。
答案 2 :(得分:0)
阅读手册页是关键,但TLDR是如果没有足够的内存在前一个块的后端放大,它将获得一个新的内存块,将旧数据复制到其中,以及返回新块的地址。不应使用旧地址,最典型的realloc语句如下所示
a = realloc(a, 200000 * sizeof(int));
这样你就不会意外地使用可能错误的旧值。
它无法更改指针中的地址,因为它是按值传递的,因此在函数中更改它只会更改本地副本。
编辑:每个风向标的绝对正确评论,更安全的路线将是
void * b = realloc(a, 200000 * sizeof(int));
if ( b ) {
a = b;
} else {
;;; /* error handler here */
}
答案 3 :(得分:0)
简单的realloc
实施应该回答您的问题:
void * realloc(void * ptr, size_t desired_size) {
size_t allocated_size = _allocated_size_of(ptr);
if (allocated_size < desired_size) {
void * new_ptr = malloc(desired_size);
memcpy(new_ptr, ptr, allocated_size);
free(ptr);
ptr = new_ptr;
}
return ptr;
}
malloc
及相关功能并不总是精确分配所需的尺寸。他们经常分配超过所需的大小。存储器分配函数保留了一些隐藏数据,这允许由malloc
或相关函数分配的指针用于查找已分配的存储器块大小。如何理解这一点并不是必须的,但是一些非常简单的实现只是在指针返回*(((size_t)ptr)-1)
之前的空间中存储大小。
答案 4 :(得分:0)
如果realloc()
返回的指针与您传入的指针不同(大部分时间都是这样),那么您传入的指针不再属于您,并且您没有业务知道或关心什么成为它。它可能会改变它的内容,也可能不会。但是你不再被允许访问它,所以你可以不关心它。
答案 5 :(得分:0)
如果&#39; a&#39;指向一个有效的内存块(来自之前的malloc / realloc / calloc),然后重新分配调用将尝试使用您请求的新大小提供一块内存
realloc调用的格式应为*tmp = realloc (a ...
必须测试realloc的返回值
如果它为NULL,则realloc无法分配所请求的内存,这就会导致&#39; a&#39;作为有效指针
然后,您负责处理&#39; a&#39;指向的任何数据。 (保存/丢弃它)你负责free
&#39; a&#39;指向的内存。
如果realloc调用成功,请创建b = tmp
,现在&#39; b&#39;是指向内存块的新指针 - 起始位置是否与&#39; a&#39;相同无关紧要。或者不同。 &#39;一个&#39;不再是一个有效的内存分配指针,虽然进一步的错误将取决于是否&#39; a&#39;指向您的程序所拥有的内存 - 基本上如果a == b,&#39; a&#39;可以在没有明显错误的情况下访问。
有效*tmp = realloc(a ...
&amp; b = tmp;
:
1)如果重新分配的存储器的起始位置不变:(a == b)
它将分配所请求的内存
但是在valgrind下运行它会看到错误消息:
无效的free()/ delete / delete [] / realloc()
无效
地址0x51fc040是大小为256的块内的0字节空闲&n; d
在这种情况下,realloc无法释放&#39; a&#39;
指向的内存
再次在这种情况下&#39; a&#39;仍然可以访问,因为它是指向分配给你的程序的内存的指针
2)如果重新分配的内存的起始位置发生了变化:(a!= b)
它会失败,Valgrind会显示如下输出:
地址:0x1e89010
地址b:0x7f2c5893c010
a realloc:0x1e89010
`./test15' ;:realloc()出错:旧的大小无效:0x0000000001e89010
并试图访问&#39; a&#39;将失败 - 甚至试图打印它作为指针失败的值,大概是因为它不再指向程序拥有的内存
换句话说,使用&#39; a&#39;在b = realloc(a ...
之后是未定义的行为
以上评论基于使用以下代码:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *a = NULL, *b = NULL, *c = NULL;
/* initial allocation */
a = malloc(256);
if( a == NULL) return (1);
printf("address of a: %p\n", a);
/* reallocation 'b' MAY be same as 'a' - try much larger allocations */
void *tmp = realloc(a, 512);
if ( !tmp ) {
free(a);
return (1);
} else {
b = tmp;
}
printf("address of b: %p\n", b);
/* see what 'a' is now - this MAY crash the program*/
printf("a after realloc: %p\n", a);
/* 'a' may not be a valid pointer - try using it for another realloc */
c = realloc(a, 256);
/* Valgrind shows that memory could not be free'd or 'a' was not valid allocated memory */
printf("return value of c: %p\n", c);
if (c != NULL) {
free(c);
printf("'c' allocated\n");
} else {
free(b);
printf("'c' not allocated\n");
}
return 0;
}