C语言从文件读取字符串拆分失败,求代码逻辑排查
问题分析与修复
问题描述
需要拆分的输入字符串:
"CristinaRodriguezRiveraComputacion210302414RamiroSilvaPerezIndustrial217890453PatriciaDuranSanchezCivil215643525RaulColinGranadosComputacion215678342"
期望输出格式(每个字段模拟占15字节块):
Cristina Rodríguez Rivera Computación 210302414
当前代码运行后输出不符合预期,以下是原代码及修复方案:
原代码(修正转义字符后)
#include <stdio.h> #include <errno.h> #include <stdbool.h> #include <ctype.h> #include <string.h> typedef struct{ char name[15]; char father[15]; char mother[15]; char degree[15]; char id[15]; }Student; Student al; int main(){ FILE* ent = fopen("DatosEntrada.txt","r"); FILE* sal = fopen("longitud.txt","a"); if(ent != NULL){ char name[15]; char father[15]; char mother[15]; char degree[15]; char id[15]; fseek(ent, 0, SEEK_END); int longarch = ftell(ent); rewind(ent); char dinamic[longarch]; fscanf(ent,"%s",&dinamic); int longitud = strlen(dinamic); int contador=0,iterador=0; for(int i=0;i<longarch;i++){ if( isupper(dinamic[i]) ){ if( islower(dinamic[i-1]) && islower(dinamic[i+1]) ){ iterator=0; counter++; } if(counter== 0){ iterator=0; name[iterator] = dinamic[i]; iterator++; }else if(counter== 1){ father[iterator] = dinamic[i]; iterator++; }else if(counter== 2){ mother[iterator] = dinamic[i]; iterator++; }else if(counter== 3){ degree[iterator] = dinamic[i]; iterator++; } }else if( islower(dinamic[i]) ){ if(counter== 0){ name[iterator] = dinamic[i]; iterator++; }else if(counter== 1){ father[iterator] = dinamic[i]; iterator++; }else if(counter== 2){ mother[iterator] = dinamic[i]; iterator++; }else if(counter== 3){ degree[iterator] = dinamic[i]; iterator++; } }else if( isdigit(dinamic[i]) ){ if( islower(dinamic[i-1]) && isdigit(dinamic[i+1]) ){ iterator=0; counter++; }else if( isupper(dinamic[i+1]) && isdigit(dinamic[i-1]) ){ id[iterator] = dinamic[i]; counter=0; printf("(%s,%s,%s,%s,%s)\n",name,father,mother,degree,id); strcpy(al.name,name); strcpy(al.father,father); strcpy(al.mother,mother); strcpy(al.degree,degree); strcpy(al.id,id); fwrite(&al,sizeof(Student), 1, sal); } if(counter== 4){ id[iterator] = dinamic[i]; iterator++; } } } fclose(ent); fclose(sal); }else{ fprintf(stdout, "ERROR: %s", strerror(errno)); } }
修复后代码
#include <stdio.h> #include <errno.h> #include <stdbool.h> #include <ctype.h> #include <string.h> typedef struct{ char name[15]; char father[15]; char mother[15]; char degree[15]; char id[15]; }Student; Student al; int main(){ FILE* ent = fopen("DatosEntrada.txt","r"); FILE* sal = fopen("longitud.txt","a"); if(ent != NULL){ char name[15] = {0}; char father[15] = {0}; char mother[15] = {0}; char degree[15] = {0}; char id[15] = {0}; fseek(ent, 0, SEEK_END); int longarch = ftell(ent); rewind(ent); char dinamic[longarch]; fscanf(ent,"%s",dinamic); // 修正:数组名无需取地址 int longitud = strlen(dinamic); int contador=0, iterador=0; for(int i=0; i<longitud; i++){ // 修正:用字符串长度循环,避免处理无效字符 if(isupper(dinamic[i])){ // 处理字段切换:仅当当前大写字母前后都是小写时,判定为新字段开头 if(i > 0 && i < longitud-1 && islower(dinamic[i-1]) && islower(dinamic[i+1])){ iterador = 0; contador++; } // 写入字符时限制长度,避免数组溢出 if(contador == 0 && iterador < 14){ name[iterador++] = dinamic[i]; }else if(contador == 1 && iterador <14){ father[iterador++] = dinamic[i]; }else if(contador == 2 && iterador <14){ mother[iterador++] = dinamic[i]; }else if(contador == 3 && iterador <14){ degree[iterador++] = dinamic[i]; } } else if(islower(dinamic[i])){ if(contador == 0 && iterador <14){ name[iterador++] = dinamic[i]; }else if(contador == 1 && iterador <14){ father[iterador++] = dinamic[i]; }else if(contador == 2 && iterador <14){ mother[iterador++] = dinamic[i]; }else if(contador == 3 && iterador <14){ degree[iterador++] = dinamic[i]; } } else if(isdigit(dinamic[i])){ // 切换到ID字段:前一个字符是小写字母 if(i >0 && islower(dinamic[i-1])){ iterador = 0; contador++; } // 写入ID字符 if(contador ==4 && iterador <14){ id[iterador++] = dinamic[i]; } // 判定学生数据结束:下一个字符是大写字母(下一个学生开头) if(i < longitud-1 && isupper(dinamic[i+1])){ // 添加字符串终止符,避免乱码 name[14] = '\0'; father[14] = '\0'; mother[14] = '\0'; degree[14] = '\0'; id[iterador] = '\0'; // 输出预期格式 printf("%s %s %s %s %s\n", name, father, mother, degree, id); // 安全复制到结构体,避免溢出 strncpy(al.name, name, 14); al.name[14] = '\0'; strncpy(al.father, father,14); al.father[14] = '\0'; strncpy(al.mother, mother,14); al.mother[14] = '\0'; strncpy(al.degree, degree,14); al.degree[14] = '\0'; strncpy(al.id, id,14); al.id[14] = '\0'; fwrite(&al,sizeof(Student), 1, sal); // 重置计数器与数组,处理下一个学生 contador = 0; iterador =0; memset(name,0,sizeof(name)); memset(father,0,sizeof(father)); memset(mother,0,sizeof(mother)); memset(degree,0,sizeof(degree)); memset(id,0,sizeof(id)); } } } // 处理最后一个学生(字符串末尾无大写字母的情况) if(contador ==4){ id[iterador] = '\0'; name[14] = '\0'; father[14] = '\0'; mother[14] = '\0'; degree[14] = '\0'; printf("%s %s %s %s %s\n", name, father, mother, degree, id); strncpy(al.name, name,14); al.name[14] = '\0'; strncpy(al.father, father,14); al.father[14] = '\0'; strncpy(al.mother, mother,14); al.mother[14] = '\0'; strncpy(al.degree, degree,14); al.degree[14] = '\0'; strncpy(al.id, id,14); al.id[14] = '\0'; fwrite(&al,sizeof(Student), 1, sal); } fclose(ent); fclose(sal); }else{ fprintf(stdout, "ERROR: %s", strerror(errno)); } return 0; }
核心修复说明
- 变量名统一:修正原代码中
contador/counter、iterador/iterator混用的问题,避免未定义行为。 - 字符串终止符:所有字符数组添加
\0终止符,解决打印乱码问题。 - 边界越界防护:访问
dinamic[i-1]/dinamic[i+1]前先判断索引有效性,避免数组越界。 - 循环逻辑修正:使用字符串实际长度而非文件长度循环,避免处理无效空字符。
- 字段切换优化:简化ID字段的切换条件,修正学生数据结束的判定逻辑,确保分割准确。
- 溢出防护:写入字符时限制长度不超过14(留位置给终止符),使用
strncpy代替strcpy避免数组溢出。 - 输入修正:去掉
fscanf中dinamic前的&,数组名本身就是指针。
内容的提问来源于stack exchange,提问作者SwagKiller
相关产品推荐
相关产品推荐

