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

C语言如何合并两个结构体数组 解决出现乱码或段错误的问题

问题根因分析
  • 数组索引逻辑错误:C语言数组为0基索引,代码中所有遍历逻辑都从下标1开始,既漏读了两个源数组的第一个元素,也导致合并后的数组存在未初始化的空位,最终遍历到j <= total时直接越界访问了数组外未申请的内存,是触发段错误、乱码的核心原因。
  • 缺少必要头文件:代码用到了strcmp、strdup、memset、calloc等函数,未引入<string.h>、<stdlib.h>头文件,存在隐式声明问题,运行行为未定义。
  • 入参无效访问:get_item_entries函数开头直接打印未赋值的*count,调用时传入的计数变量初始值为-1,属于无效内存访问。
  • 合并长度不匹配:实际存入合并数组的元素总个数为(HDD_count-1)+(ext_count-1),但申请内存和最终遍历时用的是HDD_count+ext_count的总长度,大量未初始化的指针被访问导致乱码。
修复后的完整代码
#include <stdio.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/syscall.h>      
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#define log_info printf
typedef struct
{
    char* name;
} entry_t;

/* qsort结构体按名称比较函数 */
static int struct_cmp_by_name(const void* a, const void* b)
{
    const entry_t* ia = (const entry_t*)a;
    const entry_t* ib = (const entry_t*)b;
    return strcmp(ia->name, ib->name);
}

entry_t* get_item_entries(const char* dirpath, int* count)
{
    struct dirent* dent;
    char buffer[512]; // 固定缓冲区
    int dfd = 0, n, r = 1;
    entry_t* p = NULL;

loop:
    n = 0;
    dfd = open(dirpath, O_RDONLY, 0);
    if (dfd < 0)
    {
        printf("Invalid directory. (%s)\n", dirpath);
        *count = -1;
        return NULL;
    }

    memset(buffer, 0, sizeof(buffer));
    while (syscall(SYS_getdents, dfd, buffer, sizeof(buffer)) != 0)
    {
        dent = (struct dirent*)buffer;
        while (dent->d_fileno)
        {
            // 跳过.和..
            if (!strncmp(dent->d_name, "..", 2) || !strncmp(dent->d_name, ".", 1)) 
                goto skip_dent;

            switch (r)
            {
                // 第一轮仅计数
                case 1:
                    if (dent->d_fileno == 0) goto skip_dent;
                    break;
                // 第二轮存储文件名
                case 0: 
                    p[n].name = strdup(dent->d_name); 
                    break;
            }
            n++;
        skip_dent:
            dent = (struct dirent*)((void*)dent + dent->d_reclen);
            if (dent == (void*)&buffer[512]) break; // 缓冲区读完重新填充
        }
        memset(buffer, 0, sizeof(buffer));
    }
    close(dfd);

    // 第一轮结束后分配内存
    if (!p)
    {
        p = calloc(n, sizeof(entry_t));
        *count = n;
        printf("loop: %d, count:%d\n", r, *count); // 移到赋值后避免访问无效值
    }

    // 第一轮结束进入第二轮
    r--; 
    if (!r) goto loop;

    printf("%d items at %p\n", *count, (void*)p);
    qsort(p, *count, sizeof(entry_t), struct_cmp_by_name);
    return p;
}

int main(int argc, char* argv[])
{
    int HDD_count = 0;
    int ext_count = 0;
    entry_t* e = NULL;

    entry_t* HDD = get_item_entries("/mnt/f/n", &HDD_count);
    entry_t* ext = get_item_entries("/mnt/f/dls", &ext_count);

    if (HDD_count < 0 || ext_count < 0) {
        printf("读取目录失败\n");
        return 1;
    }

    uint32_t total = ext_count + HDD_count;
    e = malloc(sizeof(entry_t) * total);
    if (e != NULL)
    {
        // 修复为0基索引遍历
        for (int i = 0; i < HDD_count; i++)
        {
            log_info("HDD[%i].name %s\n", i, HDD[i].name);
            e[i].name = strdup(HDD[i].name);
        }
        // 修复合并索引计算
        for (int i = 0; i < ext_count; i++)
        {
            log_info("ext[%i].name %s\n", i, ext[i].name);
            e[i + HDD_count].name = strdup(ext[i].name);
        }
    }
    else
    {
        printf("Failed to Allocate the Array\n");
        return 1;
    }

    char tmp[256];
    // 修复遍历边界,避免越界
    for(int j = 0; j < total; j++)
    {   
        snprintf(tmp, sizeof(tmp), "%s", e[j].name);
        log_info("%i:%s\n", j , tmp);
    }

    // 内存释放逻辑避免泄漏
    for (int i = 0; i < HDD_count; i++) free(HDD[i].name);
    free(HDD);
    for (int i = 0; i < ext_count; i++) free(ext[i].name);
    free(ext);
    for (int i = 0; i < total; i++) free(e[i].name);
    free(e);

    return 0;
}
额外优化建议
  • 避免使用goto实现循环,可改用普通的for/while循环提升可读性
  • 可以直接使用标准库的readdir接口替代直接调用SYS_getdents系统调用,兼容性更好
  • 可增加更多空指针判断逻辑,避免极端场景下访问空指针触发崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 17:06:03