You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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语言对二维数组的类型支持,避免手动计算偏移,代码更直观且不易出错。

  1. 修改函数声明和定义的参数类型:
    将int *score改为int (*score)[COURSE],这表示score是一个指向长度为COURSE的int数组的指针(也就是二维数组的行指针)。

  2. 函数内部直接用数组下标访问:
    不需要再手动计算偏移,直接用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 22:07:46