realloc 将对旧指针做什么
what will realloc do to the old pointer
我对 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
指针a还是指向同一个地址,只是内容变了。
阅读手册页是这里的关键,但是TLDR是如果在前一个块的后端没有足够的内存来放大,它会得到一个新的内存块,将旧数据复制到其中, 和 return 新块的地址。不应使用旧地址,最典型的 realloc 语句如下所示
a = realloc(a, 200000 * sizeof(int));
这样你就不会不小心使用了可能错误的旧值。
它不能改变指针中的地址,因为它是按值传递的,所以在函数中改变它只是改变本地副本。
编辑:根据 Weather Vane 的绝对正确评论,更安全的路线是
void * b = realloc(a, 200000 * sizeof(int));
if ( b ) {
a = b;
} else {
;;; /* error handler here */
}
Pointer a still point to the same address, but the content is changed.
那是因为 realloc()
可能首先尝试增加 a
指向的块的大小。但是,它可以改为分配一个新块,将数据(或尽可能多的数据)复制到新块,然后释放旧块。你真的不应该在调用 b = realloc(a, 200000 * sizeof(int))
之后使用 a
因为 realloc
调用可能会将块移动到新位置,使 a
指向不再分配的内存。请改用 b
。
一个简单的 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)
.
之前将大小存储在 space 中
如果realloc()
returns一个指针与你传入的指针不同(大多数时候会这样),那么你传入的指针不再属于你,你有没有企业知道或关心它会变成什么样子。它可能会更改其内容,也可能不会。但是你不再被允许访问它,所以它与你无关。
realloc
返回的值告诉你它是成功还是失败。
b = realloc(a, 200000 * sizeof(int));
如果失败,它returns一个空指针,a
仍然指向原始未修改的内存块(当然b
是一个空指针)。
如果成功,则b
指向一个(可能是新分配的)内存块,a
的值为不确定。如果它能够在与旧块相同的位置分配新块(通过在适当的位置增加或缩小块),那么 b
将等于 a
- 但测试它,或者即使引用 a
的值,也有未定义的行为。如果它必须重新定位块,那么 realloc
将在复制数据后完成相当于 free(a)
的操作。在任何一种情况下,最好将 a
设置为 NULL
以避免意外引用其(现在不确定的)值。
请注意 realloc
可以重新定位块,即使新大小更小。
如果 'a' 指向一个有效的内存块(来自之前的 malloc/realloc/calloc),则 realloc 调用将尝试提供一个具有您请求的新大小的内存块
realloc 调用的格式应为 *tmp = realloc (a ...
必须测试来自 realloc 的 return 值
如果为 NULL,则 realloc 无法分配请求的内存,这使得 'a' 成为有效指针
然后您负责处理 'a' 指向的任何数据(保存/丢弃)并且您负责 free
ing 'a'
指向的内存
如果 realloc 调用成功 make b = tmp
现在 'b' 是指向内存块的新指针 - 起始位置是否与 [=49= 相同并不重要] 或不同。 'a' 不再是有效的内存分配指针,尽管进一步的错误将取决于 'a' 是否指向您的程序拥有的内存 - 基本上如果 a == b,'a' 可以是访问没有明显错误。
经过有效的 *tmp = realloc(a ...
& b = tmp;
:
1) 如果重新分配内存的起始位置不变:(a == b)
它将分配请求的内存
但是 运行 它在 valgrind 下你会看到错误信息:
无效的 free() / delete / delete[] / realloc()
地址 0x51fc040 是大小为 256 的块内的 0 字节 free'd
在这种情况下,realloc 无法释放 'a'
指向的内存
在这种情况下 'a' 仍然可以访问,因为它是指向分配给您的程序的内存的指针
2) 如果重新分配内存的起始位置发生改变:(a != b)
它会失败并且 Valgrind 显示如下输出:
地址a:0x1e89010
b地址:0x7f2c5893c010
重新分配后:0x1e89010
`./test15' 中的错误:realloc():旧大小无效:0x0000000001e89010
并尝试访问 'a' 将失败 - 即使尝试将其值作为指针打印也会失败,大概是因为它不再指向程序拥有的内存
换句话说,在 b = realloc(a ...
之后使用 '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;
}
我对 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
指针a还是指向同一个地址,只是内容变了。
阅读手册页是这里的关键,但是TLDR是如果在前一个块的后端没有足够的内存来放大,它会得到一个新的内存块,将旧数据复制到其中, 和 return 新块的地址。不应使用旧地址,最典型的 realloc 语句如下所示
a = realloc(a, 200000 * sizeof(int));
这样你就不会不小心使用了可能错误的旧值。
它不能改变指针中的地址,因为它是按值传递的,所以在函数中改变它只是改变本地副本。
编辑:根据 Weather Vane 的绝对正确评论,更安全的路线是
void * b = realloc(a, 200000 * sizeof(int));
if ( b ) {
a = b;
} else {
;;; /* error handler here */
}
Pointer a still point to the same address, but the content is changed.
那是因为 realloc()
可能首先尝试增加 a
指向的块的大小。但是,它可以改为分配一个新块,将数据(或尽可能多的数据)复制到新块,然后释放旧块。你真的不应该在调用 b = realloc(a, 200000 * sizeof(int))
之后使用 a
因为 realloc
调用可能会将块移动到新位置,使 a
指向不再分配的内存。请改用 b
。
一个简单的 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)
.
如果realloc()
returns一个指针与你传入的指针不同(大多数时候会这样),那么你传入的指针不再属于你,你有没有企业知道或关心它会变成什么样子。它可能会更改其内容,也可能不会。但是你不再被允许访问它,所以它与你无关。
realloc
返回的值告诉你它是成功还是失败。
b = realloc(a, 200000 * sizeof(int));
如果失败,它returns一个空指针,a
仍然指向原始未修改的内存块(当然b
是一个空指针)。
如果成功,则b
指向一个(可能是新分配的)内存块,a
的值为不确定。如果它能够在与旧块相同的位置分配新块(通过在适当的位置增加或缩小块),那么 b
将等于 a
- 但测试它,或者即使引用 a
的值,也有未定义的行为。如果它必须重新定位块,那么 realloc
将在复制数据后完成相当于 free(a)
的操作。在任何一种情况下,最好将 a
设置为 NULL
以避免意外引用其(现在不确定的)值。
请注意 realloc
可以重新定位块,即使新大小更小。
如果 'a' 指向一个有效的内存块(来自之前的 malloc/realloc/calloc),则 realloc 调用将尝试提供一个具有您请求的新大小的内存块
realloc 调用的格式应为 *tmp = realloc (a ...
必须测试来自 realloc 的 return 值
如果为 NULL,则 realloc 无法分配请求的内存,这使得 'a' 成为有效指针
然后您负责处理 'a' 指向的任何数据(保存/丢弃)并且您负责 free
ing 'a'
如果 realloc 调用成功 make b = tmp
现在 'b' 是指向内存块的新指针 - 起始位置是否与 [=49= 相同并不重要] 或不同。 'a' 不再是有效的内存分配指针,尽管进一步的错误将取决于 'a' 是否指向您的程序拥有的内存 - 基本上如果 a == b,'a' 可以是访问没有明显错误。
经过有效的 *tmp = realloc(a ...
& b = tmp;
:
1) 如果重新分配内存的起始位置不变:(a == b)
它将分配请求的内存
但是 运行 它在 valgrind 下你会看到错误信息:
无效的 free() / delete / delete[] / realloc()
地址 0x51fc040 是大小为 256 的块内的 0 字节 free'd
在这种情况下,realloc 无法释放 'a'
指向的内存
在这种情况下 'a' 仍然可以访问,因为它是指向分配给您的程序的内存的指针
2) 如果重新分配内存的起始位置发生改变:(a != b)
它会失败并且 Valgrind 显示如下输出:
地址a:0x1e89010
b地址:0x7f2c5893c010
重新分配后:0x1e89010
`./test15' 中的错误:realloc():旧大小无效:0x0000000001e89010
并尝试访问 'a' 将失败 - 即使尝试将其值作为指针打印也会失败,大概是因为它不再指向程序拥有的内存
换句话说,在 b = realloc(a ...
之后使用 '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;
}