realloc学习笔记

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 使用此值来确定数据处理是否成功。如果返回值小于 realsizelibcurl 会认为发生了错误,并停止传输。
  • 这个回调函数通过 realloc 动态调整内存大小,以适应从 libcurl 接收到的任意大小的数据块。

  • 将接收到的数据追加到 mem->response 中,并确保它以空字符 '\0' 结尾。

  • 如果内存分配失败,回调函数会返回 0,从而中止操作。

realloc函数

realloc 函数会将原有指针指向的数据拷贝到新的内存空间中。

当调用 realloc 时,它的行为可以分为以下几种情况:

  1. 扩展现有内存块: 如果新的内存大小比当前大小大,且在原内存块后面有足够的连续空间,realloc 可能会直接扩展原来的内存块,并返回相同的指针。此时,数据保持不变,原指针数据不会被移动。

  2. 缩小现有内存块: 如果新的内存大小比当前大小小,realloc 也可能会在原位置直接缩小内存块。数据仍保持不变。

  3. 分配新的内存块: 如果不能扩展当前内存块(比如当前内存块后面没有足够的连续空间),realloc 会分配新的内存块,并将原内存块的数据复制到新分配的内存块中。此时,原有的指针会被替换为指向新内存块的指针,而原来的内存块会被释放。

  4. 分配失败: 如果分配新的内存块失败,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 中的数据复制到新的内存位置。如果成功,原来的内存块会被释放,新的内存块地址被返回。

相关推荐
守护者1701 小时前
JAVA学习-练习试用Java实现“使用Arrays.toString方法将数组转换为字符串并打印出来”
java·学习
学会沉淀。1 小时前
Docker学习
java·开发语言·学习
Rinai_R1 小时前
计算机组成原理的学习笔记(7)-- 存储器·其二 容量扩展/多模块存储系统/外存/Cache/虚拟存储器
笔记·物联网·学习
吃着火锅x唱着歌1 小时前
PHP7内核剖析 学习笔记 第四章 内存管理(1)
android·笔记·学习
ragnwang1 小时前
C++ Eigen常见的高级用法 [学习笔记]
c++·笔记·学习
胡西风_foxww2 小时前
【es6复习笔记】rest参数(7)
前端·笔记·es6·参数·rest
Web阿成3 小时前
3.学习webpack配置 尝试打包ts文件
前端·学习·webpack·typescript
雷神乐乐3 小时前
Spring学习(一)——Sping-XML
java·学习·spring
李雨非-19期-河北工职大3 小时前
思考: 与人交际
学习