C语言分类算法仅生成单个分区文件且执行后崩溃问题排查
问题描述
实现的classificacao_interna_Func函数预期按文件总大小生成每个含M条记录的分区文件,但目前仅生成一个分区文件,程序执行后崩溃;调用的tamanho_arquivo函数在此场景返回记录数异常(实际1000条返回977,实际10条返回0),但该函数在搜索、排序场景正常工作。
1. tamanho_arquivo函数关闭传入文件指针,导致后续操作失效
代码中tamanho_arquivo函数最后调用了fclose(arquivo),但classificacao_interna_Func是将已打开的arq指针传入该函数,执行后arq被关闭,后续对arq的所有操作(fseek、fread等)均为无效操作,直接导致:
- 文件读取失败,记录数计算异常
- 后续循环无法读取更多数据,仅生成一个分区
- 访问已关闭的文件指针触发崩溃
修复方法:
移除tamanho_arquivo中的fclose(arquivo),恢复文件指针到开头后返回,由调用方负责关闭文件:
int tamanho_arquivo(FILE *arquivo) { if (arquivo == NULL) { perror("Erro ao abrir o arquivo"); return -1; } fseek(arquivo, 0, SEEK_END); long tamanho_total = ftell(arquivo); if (tamanho_total == -1) { perror("Erro ao obter o tamanho do arquivo"); return -1; } int num_registros = tamanho_total / tamanho_registro(); fseek(arquivo, 0, SEEK_SET); // 恢复指针位置,不影响调用方后续操作 return num_registros; }
同时在classificacao_interna_Func函数末尾添加fclose(arq);,关闭自身打开的文件。
2. 使用!feof(arq)作为循环条件导致读取异常
feof()仅在读取操作尝试读取文件末尾之后才会返回非零值,直接用!feof(arq)作为循环条件会导致最后一次读取失败后仍执行循环体,引发:
- 分配内存但读取失败,
v[i]指向未初始化内存 reg计数错误,导致外层循环无法正常退出
修复方法:
通过检查fread的返回值控制循环:
while (i < M) { v[i] = (TFunc*)malloc(sizeof(TFunc)); if (fread(v[i], sizeof(TFunc), 1, arq) != 1) { free(v[i]); // 读取失败,释放已分配内存 break; } i++; reg++; }
3. 函数未返回值,触发未定义行为
classificacao_interna_Func声明为int类型,但函数末尾无return语句,程序执行完该函数后会出现未定义行为,表现为崩溃或其他异常。
修复方法:
在函数末尾添加返回值,同时关闭打开的文件:
NUM_PARTITIONS = qtdParticoes; fclose(arq); return qtdParticoes;
4. 修改栈数组大小的逻辑隐患
代码中当i != M时将M = i,但v是栈上声明的数组TFunc *v[M];,其大小由函数调用时的初始M值决定,修改M变量不会改变数组实际大小。若初始M远大于实际读取的i值,虽不会直接出错,但逻辑存在冗余;若i为0,后续排序、写文件、free循环都会基于M=0执行,属于不合理分支。
修复建议:
改用临时变量存储实际读取的记录数,避免修改原M值:
int actual_count = i; // 后续排序、写文件、free操作均使用actual_count
5. 文件指针定位冗余且易出错
读取原文件时,每次循环都调用fseek(arq, (reg) * t, SEEK_SET);,但fread会自动推进文件指针,该操作不仅冗余,还可能因reg计数错误导致定位偏差。
修复建议:
移除循环内的fseek,依赖fread自动管理指针位置(需确保tamanho_arquivo已将指针恢复到文件开头)。
内容的提问来源于stack exchange,提问作者Arthur Ferreira

