C语言String Array函数返回空值,内部可打印外部无输出求助
问题分析与修复:枚举目录文件的指针错误
核心错误点
悬空指针导致未定义行为
getFiles里的buffer是栈上的局部变量,函数执行完毕后栈内存会被系统回收。你在循环中执行dirs[x] = buffer;,让所有数组元素都指向这块即将失效的栈内存。函数内部打印时栈内存还没被覆盖,所以能偶然看到一个结果,但回到main后这块内存已经无效,访问它就会出现无输出甚至程序崩溃的情况。字符串内存分配遗漏终止符空间
strlen(de->d_name)只返回字符串的有效字符长度,不包含末尾的\0。你分配内存时用length*sizeof(char),会导致strcpy写入时越界,破坏内存。正确做法是分配(length + 1) * sizeof(char)。逻辑错误导致内存泄漏
你先给dirs[x]分配了内存并完成strcpy(dirs[x], buffer);,紧接着又把dirs[x]指向buffer,等于之前的内存分配完全没用,还造成了内存泄漏。无效的内存释放代码
return dirs;之后的free代码永远不会执行,返回的数组内存无法被正确释放,需要把释放逻辑移到调用方(main函数)。未处理数组越界风险
你预设total=10,如果目录中文件数量超过10个,会导致dirs数组越界写入,破坏内存。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <dirent.h> #include <string.h> #define BUFFER_SIZE 4096 // 提前声明函数,放在main前更规范 char **getFiles(int *file_count); int main(){ int file_count = 0; char **files = getFiles(&file_count); if (files == NULL) { printf("获取文件列表失败\n"); return 1; } printf("\nFUNCTION RETURN:\n"); for (int i = 0; i < file_count; i++) { printf("%s\n", files[i]); // 先释放每个字符串的内存 free(files[i]); } // 再释放数组本身的内存 free(files); return 0; } char **getFiles(int *file_count){ // 动态扩容的初始大小 int total = 10; char **dirs = malloc(total * sizeof(char *)); if (dirs == NULL) { printf("内存分配失败\n"); return NULL; } struct dirent *de; DIR *dr = opendir("."); if (dr == NULL) { printf("打开目录失败\n"); free(dirs); return NULL; } int x = 0; while ((de = readdir(dr)) != NULL){ // 跳过.和..目录(可选,看需求) if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) { continue; } // 检查是否需要扩容数组 if (x >= total) { total *= 2; char **temp = realloc(dirs, total * sizeof(char *)); if (temp == NULL) { printf("数组扩容失败\n"); // 释放已分配的字符串内存 for (int i = 0; i < x; i++) { free(dirs[i]); } free(dirs); closedir(dr); return NULL; } dirs = temp; } int length = strlen(de->d_name); // 为字符串分配内存,包含\0的位置 dirs[x] = malloc((length + 1) * sizeof(char)); if (dirs[x] == NULL) { printf("字符串内存分配失败\n"); // 清理已分配的内存 for (int i = 0; i < x; i++) { free(dirs[i]); } free(dirs); closedir(dr); return NULL; } // 直接复制文件名到分配的内存 strcpy(dirs[x], de->d_name); x++; } closedir(dr); // 把实际文件数量返回给调用方 *file_count = x; return dirs; }
关键修改说明
- 增加
file_count参数,让调用方知道返回的数组里有多少个文件。 - 去掉了栈上的
buffer,直接把文件名复制到堆内存分配的空间里,避免悬空指针。 - 修复了字符串内存分配的长度问题,加上了
\0的位置。 - 增加了数组动态扩容逻辑,避免文件数量超过预设值导致越界。
- 完善了错误处理,在内存分配失败或目录打开失败时,清理已分配的内存再返回。
- 把内存释放的逻辑移到
main函数里,确保所有堆内存都能被正确释放。
内容的提问来源于stack exchange,提问作者Jacob Thevenot
相关产品推荐
相关产品推荐

