C语言程序指针访问异常咨询:*(score+i*n+j)疑似问题的代码修正
首先,你的指针访问表达式*(score+i*n+j)确实存在错误,这也是导致结果不符的核心原因。我们来一步步拆解问题:
核心错误:二维数组的内存偏移计算错误
C语言中,二维数组是按行优先连续存储的,你的score[STUD][COURSE]数组,每一行的长度是固定的COURSE(也就是5),而不是用户输入的n。比如当你输入n=3时,每个学生只填了3门课的成绩,但数组每行仍然占用5个int的内存空间,第二个学生的成绩是从第一个学生的第5个元素之后开始存储的。
但你的代码里用i*n +j计算偏移,相当于假设每行的长度是n,这就会导致:
- 当处理第2个学生(i=1)的第1门课(j=0)时,计算出的偏移是
1*3+0=3,指向的是第一个学生的第4个未初始化元素(score[0][3]),而不是正确的score[1][0]。 - 这种错误会读取到垃圾值,最终导致总分和平均分完全不符合预期。
至于你提供的运行示例看起来正确,大概率是巧合(比如未初始化的内存刚好被填充了正确的值),或者你实际运行的代码和贴出的不一致。
修复方案:两种可选思路
方案1:使用指向一维数组的指针(推荐)
这种方式利用C语言对二维数组的类型支持,避免手动计算偏移,代码更直观且不易出错。
修改函数声明和定义的参数类型:
将int *score改为int (*score)[COURSE],这表示score是一个指向长度为COURSE的int数组的指针(也就是二维数组的行指针)。函数内部直接用数组下标访问:
不需要再手动计算偏移,直接用score[i][j]访问第i个学生第j门课的成绩。
修改后的代码如下:
#include <stdio.h> #define STUD 30 // 最大学生数 #define COURSE 5 // 最大考试科目数 // 修改函数参数类型 void Total(int (*score)[COURSE], int sum[], float aver[], int m, int n); void Print(int (*score)[COURSE], int sum[], float aver[], int m, int n); int main(void) { int i, j, m, n, score[STUD][COURSE], sum[STUD]; float aver[STUD]; printf("请输入学生总数和课程数:\n"); scanf("%d %d",&m,&n); // 添加输入验证,避免数组越界 if (m > STUD || n > COURSE || m <= 0 || n <= 0) { printf("输入无效:学生数不能超过%d,课程数不能超过%d,且必须为正整数\n", STUD, COURSE); return 1; } printf("请输入成绩:\n"); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { scanf("%d", &score[i][j]); } } // 直接传递score即可,不需要*score Total(score, sum, aver, m, n); Print(score, sum, aver, m, n); return 0; } void Total(int (*score)[COURSE], int sum[], float aver[], int m, int n) { int i, j; for (i = 0; i < m; i++) { sum[i] = 0; for (j = 0; j < n; j++) { sum[i] += score[i][j]; // 直接用下标访问 } aver[i] = (float) sum[i] / n; } } void Print(int (*score)[COURSE], int sum[], float aver[], int m, int n) { int i, j; printf("结果:\n"); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { printf("%4d\t", score[i][j]); // 直接用下标访问 } printf("%5d\t%6.1f\n", sum[i], aver[i]); } }
方案2:修正内存偏移计算(不推荐)
如果你坚持要用int*类型的参数,需要把偏移计算中的n替换为实际的行长度COURSE,因为COURSE才是数组每行的真实长度:
修改Total和Print函数中的指针访问部分:
// Total函数里的求和语句 sum[i] = sum[i] + *(score + i * COURSE + j); // Print函数里的打印语句 printf("%4d\t", *(score + i * COURSE + j));
同时,main函数中调用时可以传递&score[0][0]或者(int*)score(把二维数组指针强制转换为int*),或者保持*score(因为*score会退化为指向score[0][0]的int*)。
不过这种方式依赖全局宏COURSE,灵活性差,手动计算偏移也容易出错,所以更推荐方案1。
额外优化:添加输入验证
我在方案1的代码里添加了输入验证逻辑,防止用户输入的学生数或课程数超过数组的最大限制(STUD和COURSE),避免数组越界导致的未知错误。
内容的提问来源于stack exchange,提问作者chess

