C语言编辑Empleado结构体数组元素时出现重复值异常求助
问题分析与修复方案
核心问题:编辑后出现重复记录的根源
你的代码中存在多处未定义行为和逻辑错误,其中**loadRecords函数的错误是导致编辑后出现重复记录的主要原因**,其他模块的未初始化变量和逻辑错误会加剧问题的随机性。
1. 修复loadRecords函数
这个函数的错误会导致程序启动时就多读一条重复记录,编辑操作后问题被放大:
int loadRecords(Empleado empleados[], char *filename) { Empleado empleado; // 将nombre数组大小改为与结构体一致,避免截断或溢出 char nombre[30]; FILE *file = fopen(filename, "r"); if (file == NULL) { // 处理文件不存在的情况 printf("Archivo no encontrado, iniciando con lista vacia.\n"); return 0; } int index = 0; // 用fscanf的返回值判断是否成功读取一条完整记录,替代feof while (fscanf(file, "%u %s %s %s %s %s %f", &empleado.cedula, nombre, empleado.apellido, empleado.departamento, empleado.cargo, empleado.fecha_ingreso, &empleado.sueldo) == 7) { empleados[index] = empleado; strncpy(empleados[index].nombre, nombre, sizeof(empleados[index].nombre)); // 修复下标计算错误:调整sizeof的括号位置 empleados[index].nombre[sizeof(empleados[index].nombre) - 1] = '\0'; index++; // 防止数组越界 if (index >= N) { printf("Limite de empleados alcanzado.\n"); break; } } fclose(file); // 别忘了关闭文件 return index; }
- 替换
feof为fscanf返回值:feof只有在读取到文件末尾后才会触发,原逻辑会在最后一次fscanf失败后仍执行循环,写入重复数据。 - 修正数组大小与下标:原
nombre仅10字节无法存储完整姓名,下标计算错误会导致字符串未正确终止,引发内存越界。
2. 修复editRecord的循环逻辑错误
原循环条件混乱且option未初始化,会导致随机行为:
int editRecord(int index, Empleado empleados[]) { bool edit = true; int option = 0, aux, aux2; // 初始化option Empleado empleadoEdit = empleados[index]; printf("Editando CI: %u\n", empleadoEdit.cedula); // 改成正确的循环条件:当edit为true时继续 while (edit) { printf("Opciones (1-Nombre 2-Apellido 3-Departamento 4-Cargo 5-Salario 6-Salir): "); scanf("%i", &option); switch (option) { case 1: printf("Ingrese el nuevo nombre: "); scanf("%s", empleadoEdit.nombre); // 去掉&,数组名本身是指针 break; case 2: printf("Ingrese el nuevo apellido: "); scanf("%s", empleadoEdit.apellido); // 去掉& break; case 3: printf("Ingrese el nuevo departamento (1-RRHH 2-Consultoria 3-Design 4-Produccion 5-Calidad 6-Distribucion): "); scanf("%i", &aux); if (aux >=1 && aux <=6) { // 增加输入合法性检查 strcpy(empleadoEdit.departamento, departamentos[aux - 1]); } else { printf("Opcion invalida.\n"); } break; case 4: printf("Ingrese el nuevo cargo (1-Gerente 2-Supervisor 3-Analista 4-Designer 5-Desarrollador 6-Auditor): "); scanf("%i", &aux2); if (aux2 >=1 && aux2 <=6) { // 增加输入合法性检查 strcpy(empleadoEdit.cargo, cargos[aux2 - 1]); } else { printf("Opcion invalida.\n"); } break; case 5: printf("Ingrese el nuevo salario: "); scanf("%f", &empleadoEdit.sueldo); // 去掉多余空格 break; case 6: edit = false; break; default: printf("Opcion invalida,intente nuevamente.\n"); break; } } empleados[index] = empleadoEdit; return 0; }
- 初始化
option:未初始化的局部变量会有随机值,导致循环行为不可预测。 - 修正数组的
scanf参数:数组名本身就是指针,不需要加&,原代码的错误写法可能导致内存写入异常。 - 增加输入合法性检查:防止用户输入超出范围的选项,避免数组越界。
3. 修复main函数的未初始化变量
option和searchMode未初始化,会导致程序启动时进入错误分支:
int main() { Empleado empleados[N]; int option = 0; // 初始化 int searchIndex; int searchMode = 0; // 初始化 Empleado searchEmpleado; int size = loadRecords(empleados, "trabajadores.in"); while (option != 7) { // ... 原菜单代码 ... } return 0; }
其他改进建议
- 实现
deleteRecord函数:通过将删除位置后的元素向前移动一位,再执行size--完成删除逻辑。 - 增强输入安全性:使用
scanf("%29s", ...)限制输入长度,防止数组溢出;处理输入缓冲区的换行符,避免后续scanf读取错误。 - 检查cedula唯一性:在
newRecord和editRecord中验证身份证号是否重复,避免生成重复记录。 - 动态内存管理:若需突破
N=200的限制,可改用malloc和realloc动态分配数组,替代静态数组。
内容的提问来源于stack exchange,提问作者ZajRJ
相关产品推荐
相关产品推荐

