C语言按Fisher-Yates序列循环读取文件夹文件时遇缓冲区溢出问题求助
问题解决:Fisher-Yates洗牌读取多文件的缓冲区溢出与打印异常
核心问题定位
- 字符串拼接缓冲区溢出:
folder1长度仅为20,每次循环都向其追加路径内容,导致内存越界,这是仅能打印第一个文件的根本原因。 - 文件句柄未释放:打开文件后未调用
fclose(pic),造成资源泄漏,影响后续文件操作。 - stdout行缓冲机制:未添加
\n时,printf输出内容会留在缓冲区,不会立即显示,导致"first test"不打印的奇怪现象。 - 全局变量冲突:全局变量
i在多个函数的循环中被复用,可能引发逻辑混乱。 - 随机种子重复初始化:每次调用洗牌函数都执行
srand(time(NULL)),短时间内调用会生成重复的随机序列。 - 函数返回值不匹配:
askCategory声明为返回char但无返回语句,触发未定义行为。
具体修复步骤
- 重构路径拼接逻辑:每次循环重新构建完整路径,避免在固定长度数组上反复追加。
- 及时关闭文件:读取完每个文件后调用
fclose(pic),释放文件资源。 - 强制刷新输出缓冲区:使用
fflush(stdout)解决无\n时输出不显示的问题。 - 将全局变量改为局部变量:在每个使用
i的函数内声明局部变量,避免跨函数干扰。 - 初始化随机种子一次:将
srand(time(NULL))移至main函数开头,确保随机序列唯一性。 - 修正函数返回值:
askCategory不需要返回值,改为void类型。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> FILE *pic; FILE *correctAns; char ch; char category[10] = ""; int secondTries = 3, correct; void askCategory() { printf("\nAnimals Weather\n"); printf("Clothes Food\n"); printf(" Fruit Jobs\n"); printf("\nWhich category of vocabulary would you like to learn? "); scanf("%s", category); } void fisherYatesShuffle(int arr[], int size){ int random, temp; for (int i = size - 1; i > 0; i--){ random = rand() % (i + 1); temp = arr[i]; arr[i] = arr[random]; arr[random] = temp; } } void loadPhoto(){ char photo[3]; int sequence[15]; for (int i = 0; i < 15; i++) sequence[i] = i; fisherYatesShuffle(sequence, 15); for(int i = 0; i < 15; i++){ // 每次循环重新构建完整路径 char full_path[50] = "ascii_art/"; strcat(full_path, category); strcat(full_path, "/"); sprintf(photo, "%d", sequence[i]); strcat(full_path, photo); pic = fopen(full_path, "r"); if (pic == NULL) { printf("Error. Cannot open the file: %s\n", full_path); continue; } printf("\n"); while ((ch = fgetc(pic)) != EOF){ printf("%c", ch); } // 强制刷新缓冲区,无需依赖\n也能立即显示 fflush(stdout); printf("first test"); rewind(pic); printf("\n"); printf("second test"); rewind(pic); printf("\n"); // 关闭文件,释放资源 fclose(pic); } } void Level1() { askCategory(); loadPhoto(); } // 补充Level2函数的空实现(原代码未提供) void Level2() { printf("Level 2 is not implemented yet.\n"); } int main(void) { int form = 0; // 仅初始化一次随机种子 srand(time(NULL)); do { printf("Enter your level of study (1-6): "); scanf("%d", &form); if (form == 1 || form == 2 || form == 3) Level1(); else if (form == 4 || form == 5 || form == 6) Level2(); else printf("Invalid input. Please input again.\n"); } while (form < 1 || form > 6); return 0; }
修复说明
- 路径拼接:改用
full_path数组每次重新构建完整路径,避免了原代码中folder1被反复追加导致的缓冲区溢出。 - 文件关闭:每次循环结束前调用
fclose(pic),确保文件资源被正确释放。 - 缓冲区刷新:添加
fflush(stdout)解决了无\n时输出不显示的问题。 - 局部变量:将循环变量
i改为函数内的局部变量,避免全局变量冲突。 - 随机种子:将
srand移至main开头,确保每次运行的随机序列唯一。 - 函数修正:将
askCategory改为void类型,消除返回值不匹配的问题。
内容的提问来源于stack exchange,提问作者luna
相关产品推荐
相关产品推荐

