C语言程序出现Segmentation Fault,i/j/k值超出数组范围求助
C语言程序段错误(Segmentation Fault)排查与修复
问题概述
编写的C语言程序旨在从datospersonas.txt文件读取包含年龄(edad)、分数(notas)、性别(sexo)的结构体数据,进行统计分析时触发Segmentation Fault错误。通过打印索引变量i、j、k的值,发现这些值超出了数组定义的范围,这是导致崩溃的直接原因。手动创建测试文件后问题仍未解决,原程序及数据生成程序代码如下。
原主程序代码
#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <time.h> #include <windows.h> int i = 0, j = 0, k = 0; struct persona { int edad; //EDAD DE 12-65// int notas; //NOTAS DE 0-10// char sexo; //SEXO 1=MASCULINO Y 2=FEMENINO// char exi; //EXI 1=SI 2=NO }; struct reg { int notas; int contex; int cont; }; struct reg A[7][6][3]; int grupoedad(struct persona p) { if( p.edad < 12) { printf("\nexiste un error en la edad"); } else if(p.edad < 16) { return 1; } else if(p.edad < 26) { return 2; } else if(p.edad < 36) { return 3; } else if(p.edad < 46) { return 4; } else if(p.edad < 56) { return 5; } else if(p.edad < 66) { return 6; } } int niveling(struct persona p) { if(p.notas < 2) { return 1; } else if(p.notas < 4) { return 2; } else if(p.notas < 6) { return 3; } else if(p.notas < 8) { return 4; } else if(p.notas <=10) { return 5; } } int femasc(struct persona p) { if(p.sexo == 'M'){ return 1; } else if(p.sexo == 'F') { return 2; } } void etario(int j, char grupoed[10]) //ASIGNAMOS LOS RANGOS ETARIOS// { switch(j) { case(1): strcpy(grupoed, "12-15"); break; case(2): strcpy(grupoed, "16-25"); break; case(3): strcpy(grupoed, "26-35"); break; case(4): strcpy(grupoed, "36-45"); break; case(5): strcpy(grupoed, "46-55"); break; case(6): strcpy(grupoed, "56-65"); default: printf("\nHa ocurrido un error"); } } //void matrizcero(struct reg A[7][6][3], int i, int j, int k) { // for (i = 1; i < 7; i++) // { //for (j = 1; j < 6; j++) // { // for (k = 1; k < 3; k++) // { // A[i][j][k].contex = 0; // A[i][j][k].cont = 0; //A[i][j][k].notas = 0; // } // } // } // } int main() { struct reg { int notas; int contex; int cont; }; struct reg A[7][6][3]; struct persona p; int rangomay, rangomen, rangointmay, resmay, resmen, jex, jmay, jmen, NIV, GRUPOET, sexo, cantidadM, califM, cantidadF, califF, grupoetario; // matrizcero(A[7][6][3], i, j, k); char grupoed[10]; float prom_m, prom_f; FILE *entrada; //ABRO ARCHIVO entrada=fopen("datospersonas.txt","ab"); if (entrada == NULL){ exit(1); printf("\nError al abrir el archivo"); } else { printf("\nArchivo abierto exitosamente!"); } while(!(feof(entrada))) { fread(&p,sizeof(p),1,entrada); // void niveling(struct persona p, int i); // grupoedad(struct persona p, int j); // femasc(struct persona p, int k); i = niveling(p); j = grupoedad(p); k = femasc(p); printf("\n%d",i); printf("\n%d",j); printf("\n%d",k); A[i][j][k].notas = A[i][j][k].notas + p.notas; A[i][j][k].cont = A[i][j][k].cont; if(p.exi = 'S') { A[i][j][k].contex = A[i][j][k].contex + 1; } } for(i = 0; i < 5; i++) { //TOTALIZO HOMBRES Y MUJERES for(j = 0; j < 6; j++) { A[i][j][3].notas = A[i][j][3].notas + A[i][j][2].notas; A[i][j][3].cont = A[i][j][3].cont + A[i][j][2].cont; A[i][j][3].contex = A[i][j][3].contex + A[i][j][2].contex; } } for(j = 0; j < 6; j++) { for(i = 0; i < 5; i++) { cantidadM = cantidadM + A[i][j][1].cont; califM = califM + A[i][j][1].notas; } } prom_m = califM / cantidadM; //PROMEDIO DE CALIFICACIONES DE LOS HOMBRES for(j = 0; j < 6; j++) { for(i = 0; i < 5; i++) { cantidadF = cantidadF + A[i][j][2].cont; califF = califF + A[i][j][2].notas; } } prom_f = califF / cantidadM; //PROMEDIO DE CALIFICACIONES MUJERES for(k = 0; k < 2; k++) { for(i = 0; i < 5; i++) { for(j = 0; j < 6; j++) { A[6][j][k].cont = A[6][j][k].cont + A[i][j][k].cont; A[6][j][k].contex = A[6][j][k].contex + A[i][j][k].cont; A[6][j][k].notas = A[6][j][k].notas + A[i][j][k].notas; } } } for(j = 0; j < 6; j++) { A[6][j][3].cont = A[6][j][1].cont + A[6][j][2].cont; A[6][j][3].cont = A[6][j][1].contex + A[6][j][2].contex; A[6][j][3].notas = A[6][j][1].notas + A[6][j][2].notas; } resmay = A[6][1][3].contex; for(j = 0; j < 6; j++) { if(A[6][j][3].contex > resmay) { resmay = A[6][j][3].contex; jex = j; } } for(j = 0; j < 6; j++) { for(k = 0; k < 3; k++) { A[7][j][k].notas = A[6][j][k].notas / A[6][j][k].cont; } } resmen = A[7][1][3].notas; resmay = A[7][1][3].notas; for(j = 0; j < 6; j++) { if(A[7][j][3].notas > resmay) { resmay = A[7][j][3].notas; jmay = j; } else { if(A[7][j][3].notas < resmen) { resmen = A[7][j][3].notas; jmen = j; } } } etario(jmay, grupoed); printf("\nEl rango etario con mayor calificacion en promedio fue el comprendido entre: %s%s", grupoed, " años"); etario(jmen, grupoed); printf("\nEl rango etario con menor calificacion en promedio fue el comprendido entre: %s%s", grupoed, " años"); printf("\nEl promedio de calificaciones en femeninos fue: %f", prom_f); printf("\nEl promedio de calificaciones en masculinos fue: %f", prom_m); etario(jex, grupoed); printf("\nEl rango etario con mayor interes en rendir examenes internacionales es el comprendido entre: %s", grupoed, "años"); fclose(entrada); system("pause"); return 0; }
原数据生成程序代码
#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <time.h> struct persona { int edad; //EDAD DE 12-65// int notas; //NOTAS DE 0-10// char sexo; //SEXO 1=MASCULINO Y 2=FEMENINO// char exi; //EXI 1=SI 2=NO }; void generacion() { FILE *entrada; entrada=fopen("datospersonas.txt","ab"); if (entrada == NULL){ exit(1); } fclose(entrada); } int main() { int s; int exi; generacion(); persona p; FILE* entrada; entrada=fopen("datospersonas.txt","ab"); srand(time(NULL)); for (size_t i=0;i<650; i++) { p.edad =(rand() %54)+12; p.notas =(rand() %10)+1; s=(rand() %2)+1; if(s == 1){ p.sexo='M'; } else{ p.sexo='F'; } exi=(rand() %2)+1; if(exi == 1){ p.exi='S'; } else{ p.exi='N'; } fwrite(&p, sizeof(struct persona),1,entrada); printf("edad: %d\n",p.edad); printf("nota: %d\n",p.notas); printf("sexo: %c\n",p.sexo); printf("esta interesado en rendir examenes internacionales: %c\n",p.exi); } fclose(entrada); return 0; }
核心问题分析
程序崩溃的根源是数组索引越界,但存在多个触发该问题的前置错误:
- 索引规则不匹配:数组
A[7][6][3]采用0-based索引(有效范围0-6、0-5、0-2),但grupoedad返回1-6,niveling返回1-5,femasc返回1-2,直接导致索引越界。 - 函数无默认返回值:
grupoedad、niveling、femasc在输入不符合条件时未返回值,会返回垃圾值作为索引,进一步加剧越界风险。 - 文件打开模式错误:主程序用
"ab"(追加二进制)模式打开要读取的文件,应使用"rb"(只读二进制)模式。 - 未初始化变量:
cantidadM、califM等统计变量未初始化,数组A未清零,导致统计结果异常或垃圾值干扰。 - feof使用错误:
while(!feof(entrada))会导致多读一次无效数据,触发对非法结构体的索引计算。 - 赋值/比较混淆:
if(p.exi = 'S')是赋值操作而非比较,会强制修改p.exi的值并始终为真。 - 数组越界访问:多处出现
A[i][j][3](第三维最大索引为2)、A[7][j][k](第一维最大索引为6)的非法访问。
修复方案
针对上述问题逐一修正:
1. 统一索引为0-based
修改三个索引函数,返回符合数组范围的0-based值:
grupoedad返回0-5(对应原1-6的年龄组)niveling返回0-4(对应原1-5的分数段)femasc返回0-1(对应原1-2的性别)
2. 给函数添加默认返回值
在每个索引函数末尾添加默认返回值,处理异常输入(如年龄<12、分数超出范围等)。
3. 修正文件打开模式
主程序中修改fopen参数为"rb",确保以只读模式打开文件。
4. 初始化变量与数组
- 初始化统计变量
cantidadM、califM等为0 - 用循环或
memset初始化数组A的所有成员为0
5. 修正文件读取逻辑
用fread的返回值判断是否读取成功,替代feof:
while(fread(&p, sizeof(p), 1, entrada) == 1)
6. 修正赋值/比较错误
将if(p.exi = 'S')改为if(p.exi == 'S')。
7. 修正数组越界访问
- 删除所有
A[i][j][3]的访问,调整统计逻辑到合法索引范围内 - 删除
A[7][j][k]的访问,改用合法的第一维索引存储平均值
修正后的主程序代码
#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <time.h> #include <windows.h> #include <string.h> struct persona { int edad; // EDAD DE 12-65 int notas; // NOTAS DE 0-10 char sexo; // SEXO M=MASCULINO F=FEMENINO char exi; // EXI S=SI N=NO }; struct reg { int notas; int contex; int cont; }; // 调整数组大小以支持性别合计(第三维增加到3:0=M,1=F,2=合计) struct reg A[6][6][3]; // 分数段0-4,年龄组0-5,性别0-2 int grupoedad(struct persona p) { if(p.edad < 12 || p.edad >65) { printf("\nError en edad: %d", p.edad); return 0; // 默认返回第一个年龄组 } else if(p.edad < 16) { return 0; } else if(p.edad < 26) { return 1; } else if(p.edad < 36) { return 2; } else if(p.edad < 46) { return 3; } else if(p.edad < 56) { return 4; } else { // 56-65 return 5; } } int
相关产品推荐
相关产品推荐

