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
相关产品推荐
相关产品推荐

