You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用malloc和realloc动态重分配结构体数组的技术求助

解决用malloc/realloc创建ELF节结构体数组的问题

我看你在尝试用malloc和realloc构建ELF节的结构体数组时遇到了瓶颈,从你给出的代码片段来看,核心问题是缺少动态分配数组的关键逻辑,同时结构体成员的指针处理也存在潜在的生命周期风险。下面我会一步步帮你梳理和修正这些问题:

1. 先搞定结构体数组的初始化(malloc)

在main函数里,你已经算出了sections_count,这时候首先要分配一块能装下sections_count个struct _section的内存:

// 拿到sections_count之后执行
struct _section *exe_sect_array = malloc(sections_count * sizeof(struct _section));
if (exe_sect_array == NULL) {
    perror("malloc failed");
    // 记得先清理已打开的ELF资源、关闭文件再退出
    exit(EXIT_FAILURE);
}

2. 修正get_exe_sections函数,适配数组填充

你当前的get_exe_sections只能处理单个结构体,而且直接操作传入的指针,没有考虑数组的索引。更重要的是,直接赋值elf_strptr和data->d_buf的指针会有悬空风险——这些指针指向ELF库内部的内存,当你关闭ELF文件后,这块内存会被释放,导致你的结构体成员变成无效指针。

更安全的get_exe_sections版本

// 返回bool表示填充是否成功,方便上层做错误处理
bool get_exe_sections(struct _section *sect, Elf *elf, GElf_Ehdr *ehdr, GElf_Shdr *shdr, Elf_Data *data) {
    // 拷贝节名称:用strdup复制一份,避免依赖ELF内部的字符串表
    char *name = elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name);
    if (name == NULL) return false;
    sect->sectName = strdup(name);
    if (sect->sectName == NULL) return false;

    sect->start_addr = shdr->sh_addr;
    sect->end_addr = shdr->sh_addr + shdr->sh_size;

    // 拷贝节的字节数据:malloc一块新内存,把data里的内容复制过去
    sect->bytes = malloc(shdr->sh_size);
    if (sect->bytes == NULL) {
        free(sect->sectName); // 已经分配的名称要释放,避免内存泄漏
        return false;
    }
    memcpy(sect->bytes, data->d_buf, shdr->sh_size);

    return true;
}

在main里循环填充数组

接下来你需要遍历每个ELF节,把数据填充到数组的对应位置:

int i = 0;
Elf_Scn *scn = NULL;
// 遍历所有节
while ((scn = elf_nextscn(elf, scn)) != NULL && i < sections_count) {
    GElf_Shdr shdr;
    if (gelf_getshdr(scn, &shdr) == NULL) {
        fprintf(stderr, "Failed to get section header\n");
        break;
    }
    Elf_Data *data = elf_getdata(scn, NULL);
    if (data == NULL) {
        fprintf(stderr, "Failed to get section data\n");
        break;
    }

    // 填充数组的第i个元素
    if (!get_exe_sections(&exe_sect_array[i], elf, ehdr, &shdr, data)) {
        // 填充失败,要清理已经分配的资源
        for (int j = 0; j < i; j++) {
            free(exe_sect_array[j].sectName);
            free(exe_sect_array[j].bytes);
        }
        free(exe_sect_array);
        perror("Failed to populate section");
        exit(EXIT_FAILURE);
    }
    i++;
}

3. 如果需要动态扩展数组(用realloc)

要是你没办法提前准确获取节的数量,或者需要动态添加节,可以用realloc来扩展数组的容量:

// 初始化空数组,容量和当前元素数都设为0
struct _section *exe_sect_array = NULL;
int current_capacity = 0;
int current_count = 0;

// 在遍历节的循环中:
if (current_count >= current_capacity) {
    // 每次扩展容量,比如初始给4个位置,之后翻倍
    int new_capacity = (current_capacity == 0) ? 4 : current_capacity * 2;
    struct _section *temp = realloc(exe_sect_array, new_capacity * sizeof(struct _section));
    if (temp == NULL) {
        // 扩展失败,清理已分配的所有资源
        for (int j = 0; j < current_count; j++) {
            free(exe_sect_array[j].sectName);
            free(exe_sect_array[j].bytes);
        }
        free(exe_sect_array);
        perror("realloc failed");
        exit(EXIT_FAILURE);
    }
    exe_sect_array = temp;
    current_capacity = new_capacity;
}

// 填充当前位置的元素
if (get_exe_sections(&exe_sect_array[current_count], elf, ehdr, &shdr, data)) {
    current_count++;
} else {
    fprintf(stderr, "Failed to add section\n");
    break;
}

4. 别忘了释放内存!

使用完数组后,一定要逐个释放结构体里的动态分配成员,最后再释放数组本身,避免内存泄漏:

// 假设sections_count是实际填充的节数量
for (int j = 0; j < sections_count; j++) {
    free(exe_sect_array[j].sectName);
    free(exe_sect_array[j].bytes);
}
free(exe_sect_array);

核心注意事项

  • 指针生命周期:elf_strptr和data->d_buf的指针都是ELF库内部的,一旦你调用elf_end(elf)或者关闭文件,这些内存就会被回收,直接赋值会导致悬空指针,必须手动拷贝。
  • 错误处理:malloc、realloc、strdup都可能失败,一定要检查返回值,并且在失败时清理已经分配的资源,不然会留下内存泄漏。
  • 数组越界:操作数组时要确保循环的边界正确,不要超出数组的容量或实际填充的元素数。

内容的提问来源于stack exchange,提问作者nice_remark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:24:57