realloc学习笔记
最近用到curl做业务,引了自己写封装的curl库,看到的数据回调函数中使用了realloc函数,处理逻辑有些想不请来了,不排除这个函数是copy别人的。分析一下源码,做一下笔记。
源码
cpp
size_t STL_CURL::write_function_callback(void *data, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
CurlMemory *mem = (CurlMemory *)userp;
char *ptr = (char *)realloc((void *)(mem->response), mem->size + realsize + 1); // 注意:realloc第一个参数为空或者内存空间,注意初始化
if (ptr == NULL)
return 0; /* out of memory! */
mem->response = ptr;
memcpy(&(mem->response[mem->size]), data, realsize);
mem->size += realsize;
mem->response[mem->size] = 0;
return realsize;
}
分析
这是一个用于处理 libcurl
数据写入回调函数 STL_CURL::write_function_callback
。这个回调函数处理从服务器接收到的数据。
cpp
size_t STL_CURL::write_function_callback(void *data, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
CurlMemory *mem = (CurlMemory *)userp;
-
size_t realsize = size * nmemb;
size
是每个元素的大小(通常是字节数)。nmemb
是元素的数量。realsize
计算出从libcurl
接收到的实际数据大小,即data
指向的数据块的总大小。
-
CurlMemory *mem = (CurlMemory *)userp;
userp
是自定义的数据指针,传递给libcurl
的回调函数。在这里,它被转换为CurlMemory
类型的指针。CurlMemory
是一个用于存储接收到的数据的结构体,结构体包含一个指向存储数据的指针response
和数据的当前大小size
。
cpp
char *ptr = (char *)realloc((void *)(mem->response), mem->size + realsize + 1);
if (ptr == NULL)
return 0; /* out of memory! */
char *ptr = (char *)realloc((void *)(mem->response), mem->size + realsize + 1);
realloc
是一个标准库函数,用于调整内存块的大小。- 这里的
realloc
调整了mem->response
的内存大小,使其能够容纳现有数据mem->size
加上新接收到的数据realsize
,再加上一个额外的字节(通常用于存储字符串的终止符'\0'
)。 - 如果
mem->response
为空(例如,第一次接收到数据时),realloc
的第一个参数可以是NULL
,它会像malloc
一样分配新内存。 - 如果内存分配失败,
ptr
将是NULL
,在这种情况下,函数返回0
,表示内存不足,从而终止数据接收。
cpp
mem->response = ptr;
memcpy(&(mem->response[mem->size]), data, realsize);
mem->size += realsize;
mem->response[mem->size] = 0;
-
mem->response = ptr;
- 将新分配的内存地址存回
mem->response
,这确保了如果realloc
成功,mem->response
指向的内存块是扩展后的。
- 将新分配的内存地址存回
-
memcpy(&(mem->response[mem->size]), data, realsize);
memcpy
是标准库函数,用于将data
指向的realsize
字节数据复制到mem->response
的末尾。&(mem->response[mem->size])
计算出数据复制的目标地址,这里是mem->response
当前内容的末尾。
-
mem->size += realsize;
- 更新
mem->size
以反映新接收到的数据量。
- 更新
-
mem->response[mem->size] = 0;
- 在
mem->response
的末尾添加一个空字符'\0'
,将response
作为一个以空字符结尾的字符串。这样,数据可以被当作一个标准 C 字符串处理。
- 在
cpp
return realsize;
}
-
return realsize;
- 返回实际处理的字节数。
libcurl
使用此值来确定数据处理是否成功。如果返回值小于realsize
,libcurl
会认为发生了错误,并停止传输。
- 返回实际处理的字节数。
-
这个回调函数通过
realloc
动态调整内存大小,以适应从libcurl
接收到的任意大小的数据块。 -
将接收到的数据追加到
mem->response
中,并确保它以空字符'\0'
结尾。 -
如果内存分配失败,回调函数会返回
0
,从而中止操作。
realloc函数
realloc
函数会将原有指针指向的数据拷贝到新的内存空间中。
当调用 realloc
时,它的行为可以分为以下几种情况:
-
扩展现有内存块: 如果新的内存大小比当前大小大,且在原内存块后面有足够的连续空间,
realloc
可能会直接扩展原来的内存块,并返回相同的指针。此时,数据保持不变,原指针数据不会被移动。 -
缩小现有内存块: 如果新的内存大小比当前大小小,
realloc
也可能会在原位置直接缩小内存块。数据仍保持不变。 -
分配新的内存块: 如果不能扩展当前内存块(比如当前内存块后面没有足够的连续空间),
realloc
会分配新的内存块,并将原内存块的数据复制到新分配的内存块中。此时,原有的指针会被替换为指向新内存块的指针,而原来的内存块会被释放。 -
分配失败: 如果分配新的内存块失败,
realloc
返回NULL
,原来的内存块保持不变且不被释放。
例子:
cpp
int *arr = malloc(5 * sizeof(int)); // 分配初始内存
// 假设 arr 中已填充一些数据
// 增加大小并重新分配内存
int *new_arr = realloc(arr, 10 * sizeof(int));
if (new_arr) {
// 如果重新分配成功,arr 中的数据已被复制到 new_arr 中
arr = new_arr;
} else {
// 重新分配失败,原来的内存块仍然有效,arr 不变
}
在这个例子中,realloc
将会在必要时分配一个新的内存块,并将 arr
中的数据复制到新的内存位置。如果成功,原来的内存块会被释放,新的内存块地址被返回。