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

C语言目录遍历排序程序如何实现基于文件计数的动态内存分配

动态内存改造的极简实现方案

完全贴合你现有代码逻辑,改造成本最低,不需要重构复杂结构,直接替换掉原来的固定长度数组即可:

核心思路

不需要一开始就构建复杂的链表结构,采用带容量追踪的动态可扩容数组就可以满足需求:

  • 不再在栈上申请固定大小的结构体数组
  • 用两个变量追踪当前数组的「已存文件数」和「已申请的最大可容纳条目数」
  • 每次要新增文件条目时,检查容量是否足够,不够就用realloc把数组扩容到原来的2倍,这种方式的内存分配摊还开销极低,完全适配目录遍历的场景

具体改造步骤

  • 第一步:删掉原来的#define MAXFILE 10000和main函数里的静态结构体数组定义,换成全局的动态指针和追踪变量(对新手来说全局变量可以避免复杂的二重指针传参逻辑,降低改代码的难度):
    #include <stdlib.h>
    #include <limits.h> // 用系统定义的PATH_MAX替代硬编码256
    #include <stdio.h>
    #include <string.h>
    #include <stdint.h>
    #include <sys/stat.h>
    #include <dirent.h>
    
    struct fileList
    {
        char fName[PATH_MAX];
        off_t fileSize; // 替换unsigned int,避免4G以上大文件大小溢出
    };
    
    // 动态追踪变量,替代原来的固定数组
    int fileCount = 0;       // 已存储的文件条目数(你原来代码本来就用这个值)
    int fileCapacity = 0;    // 当前动态数组可容纳的最大条目数
    struct fileList *file_array = NULL; // 动态数组首指针,初始为空
    
  • 第二步:加一个极简的扩容检查函数,每次新增文件前调用,确保内存够存新条目:
    void ensure_array_capacity() {
        // 只有已存数达到当前容量时才需要扩容
        if (fileCount >= fileCapacity) {
            // 初始第一次存文件时申请4个条目空间,之后每次容量翻倍
            int newCapacity = fileCapacity == 0 ? 4 : fileCapacity * 2;
            // realloc会自动把原来数组里的数据拷贝到新申请的内存块
            struct fileList *temp = realloc(file_array, newCapacity * sizeof(struct fileList));
            // 必须加内存分配失败的判断,避免程序崩溃
            if (!temp) {
                perror("内存分配失败");
                exit(EXIT_FAILURE);
            }
            file_array = temp;
            fileCapacity = newCapacity;
        }
    }
    
  • 第三步:修改原来的递归遍历函数,删掉原来的数组传参(因为动态数组已经是全局管理的),把存文件的逻辑调整为先检查扩容再写入,同时修复原来重复调用stat的冗余问题:
    void rec_tav(char *path)
    {
        DIR* dir;
        struct dirent *ent;
        struct stat sb;
        char newPath[PATH_MAX];
        
        dir = opendir(path);
        if(!dir){
            return;
        }
        
        while((ent = readdir(dir)) != NULL){
            // 跳过.和..目录
            if(strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0)
                continue;
            // 拼接子路径
            strcpy(newPath,path);
            strcat(newPath,"/");
            strcat(newPath,ent->d_name);
            // 单次调用stat,去掉原来连续两次调用的冗余
            if (stat(newPath, &sb) != 0) {
                continue;
            }
            // 判断是不是普通文件
            if(S_ISREG(sb.st_mode)){
                ensure_array_capacity();
                strcpy(file_array[fileCount].fName, newPath);
                file_array[fileCount].fileSize = sb.st_size;
                fileCount++;
            }
            // 递归遍历子目录
            rec_tav(newPath);
        }
        closedir(dir);
    }
    
  • 第四步:修改main函数,去掉静态数组定义,排序、输出的逻辑完全兼容原来的写法,最后记得释放动态申请的内存,避免内存泄漏:
    int main(int argc,char **argv)
    {
        if (argc < 2) {
            fprintf(stderr, "用法: %s <需要遍历的目录路径>\n", argv[0]);
            return 1;
        }
        rec_tav(argv[1]);
        // 排序函数记得把已存的文件数当长度传进去,原来的定长数组是不需要传长度的
        sorter(file_array, fileCount);
        for(int i = 0; i < fileCount;i++)
            // 强转成intmax_t是跨平台打印off_t类型的通用写法,避免不同系统类型大小不匹配的打印错误
            printf("%jd\t%s\n", (intmax_t)file_array[i].fileSize, file_array[i].fName);
        
        // 释放动态申请的数组内存
        free(file_array);
        return 0;
    }
    

补充说明

  • 这种扩容方式和你原来的静态数组用法几乎完全一致,排序函数不需要做太大改动,只要排序时把数组首地址、实际长度传进去就行,新手很容易上手
  • 不推荐一开始用链表实现存储,链表的内存碎片化严重,而且排序的时候效率远不如连续的数组结构,对文件排序这种需要连续内存遍历的场景反而不友好

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 12:54:11