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

C语言按Fisher-Yates序列循环读取文件夹文件时遇缓冲区溢出问题求助

问题解决:Fisher-Yates洗牌读取多文件的缓冲区溢出与打印异常

核心问题定位

  1. 字符串拼接缓冲区溢出:folder1长度仅为20,每次循环都向其追加路径内容,导致内存越界,这是仅能打印第一个文件的根本原因。
  2. 文件句柄未释放:打开文件后未调用fclose(pic),造成资源泄漏,影响后续文件操作。
  3. stdout行缓冲机制:未添加\n时,printf输出内容会留在缓冲区,不会立即显示,导致"first test"不打印的奇怪现象。
  4. 全局变量冲突:全局变量i在多个函数的循环中被复用,可能引发逻辑混乱。
  5. 随机种子重复初始化:每次调用洗牌函数都执行srand(time(NULL)),短时间内调用会生成重复的随机序列。
  6. 函数返回值不匹配: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;
}

修复说明

  1. 路径拼接:改用full_path数组每次重新构建完整路径,避免了原代码中folder1被反复追加导致的缓冲区溢出。
  2. 文件关闭:每次循环结束前调用fclose(pic),确保文件资源被正确释放。
  3. 缓冲区刷新:添加fflush(stdout)解决了无\n时输出不显示的问题。
  4. 局部变量:将循环变量i改为函数内的局部变量,避免全局变量冲突。
  5. 随机种子:将srand移至main开头,确保每次运行的随机序列唯一。
  6. 函数修正:将askCategory改为void类型,消除返回值不匹配的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 10:43:28