C 程序中的幽灵正在更​​改数组元素的值,但没有声明这样做

问题描述

我在循环中定义了一堆分母,用于在未来循环中执行的一些除法,让我烦恼的是未来循环正在改变其中一些的值而没有声明这样做。正如您在代码中看到的,第 63 行中的语句是导致此类问题的原因,我在该行前后添加了一些打印语句来检查问题:

#include <stdio.h>

const int numeroComponentes=3;
const int numeroGrupos=4;

void gammaUNIFAC(double composition[],double RQParameters[][2],double gruposPorComponente[][numeroComponentes],double gammaResults[][numeroComponentes]);

int main()
{
    
    double composition[numeroComponentes]={0.5719,0.4120,0.0161};
    double RQParameters[numeroGrupos][2]={{0.9011,0.848},{0.6744,0.54},{0.5313,0.4},{1.8701,1.724}};
    double gruposPorComponente[numeroGrupos][numeroComponentes]={{0,2},{0,5},6,0},{1,0}};
    double aParameters[numeroGrupos][numeroGrupos]={{0,32.08,601.6},{15.26,15.26,290.1},{27.31,27.31,-66.44,0}};
    double Temperatura=318.0;

    double gammaResults[3][numeroComponentes];
    
    gammaUNIFAC(composition,RQParameters,gruposPorComponente,gammaResults);
    for (int i=0; i<numeroGrupos; i++) {
        for (int j=0; j<numeroComponentes; j++) {
            printf("%f\t",gammaResults[i][j]);
        }
        printf("\n");
    }
    
    return 0;
    
}

void gammaUNIFAC(double composition[],double gammaResults[][numeroComponentes]){
    
    double ri[numeroComponentes]={0};
    double qi[numeroComponentes]={0};
    double sumaGrupos[numeroComponentes]={0};
    double Xmi[numeroComponentes][numeroGrupos]={0};
    double suma_XmiTetami[numeroComponentes]={0};
    double li[numeroComponentes]={0};
    double suma_xili=0;
    double suma_xiqi=0;
    double suma_xiri=0;
    double suma_Xm=0;
    double Tetami[numeroComponentes][numeroGrupos]={0};
    
    for (int i=0; i<numeroComponentes; i++) {
        for (int j=0; j<numeroGrupos; j++) {
            ri[i]=ri[i]+RQParameters[j][0]*gruposPorComponente[j][i];
            qi[i]=qi[i]+RQParameters[j][1]*gruposPorComponente[j][i];
            sumaGrupos[i]=sumaGrupos[i]+gruposPorComponente[j][i];
        }
        printf("denominator %f\t",sumaGrupos[i]);
        printf("\n");
        for (int j=0; j<numeroGrupos; j++) {
            printf("numerator before %f\t",gruposPorComponente[i][j]);
            printf("denominator before %f\t",sumaGrupos[i]);
            Xmi[j][i] = gruposPorComponente[j][i]/sumaGrupos[i];
            printf("numerator after %f\t",gruposPorComponente[i][j]);
            printf("denominator after %f\t",sumaGrupos[i]);
            printf("\n");
            suma_XmiTetami[i] = suma_XmiTetami[i] + Xmi[j][i]*RQParameters[j][1];
        }
        printf("denominator %f\t",sumaGrupos[i]);
        printf("\n");
        li[i] = (10.0/2.0)*(ri[i] - qi[i])-(ri[i] - 1.0);
        suma_xili = suma_xili + li[i]*composition[i];
        suma_xiqi = suma_xiqi + qi[i]*composition[i];
        suma_xiri = suma_xiri + ri[i]*composition[i];
        suma_Xm = suma_Xm + sumaGrupos[i]*composition[i];
        for (int j=0; j<numeroGrupos; j++) {
            Tetami[j][i]=Xmi[j][i]*RQParameters[j][1]/suma_XmiTetami[i];
        }
        printf("\n");
    }
    
    for (int i=0; i<numeroGrupos; i++) {
        for (int j=0; j<numeroComponentes; j++) {
            if (i==0) gammaResults[i][j]=ri[j];
            if (i==1) gammaResults[i][j]=qi[j];
            if (i==2) gammaResults[i][j]=sumaGrupos[j];
        }
    }
    
}

程序执行后抛出的结果为:

denominator 1.000000    
numerator before 0.000000   denominator before 1.000000 numerator after 0.000000    denominator after 1.000000  
numerator before 0.000000   denominator before 1.000000 numerator after 0.000000    denominator after 1.000000  
numerator before 2.000000   denominator before 1.000000 numerator after 2.000000    denominator after 1.000000  
numerator before 0.000000   denominator before 1.000000 numerator after 0.000000    denominator after 1.000000  
denominator 1.000000    

denominator 6.000000    
numerator before 0.000000   denominator before 6.000000 numerator after 0.000000    denominator after 6.000000  
numerator before 0.000000   denominator before 6.000000 numerator after 0.000000    denominator after 6.000000  
numerator before 5.000000   denominator before 6.000000 numerator after 5.000000    denominator after 6.000000  
numerator before 0.000000   denominator before 6.000000 numerator after 0.000000    denominator after 0.000000  
denominator 0.000000    

denominator 7.000000    
numerator before 0.000000   denominator before 7.000000 numerator after 0.000000    denominator after 7.000000  
numerator before 6.000000   denominator before 7.000000 numerator after 6.000000    denominator after 7.000000  
numerator before 0.000000   denominator before 7.000000 numerator after 0.000000    denominator after 7.000000  
numerator before 1.000000   denominator before 7.000000 numerator after 1.000000    denominator after 0.000000  
denominator 0.000000    

1.870100    3.187800    5.174200    
1.724000    2.400000    4.396000    
1.000000    0.000000    0.000000    
0.000000    0.000000    0.000000

您可以检查结果,第一次执行第二次循环时分母没有改变,但是第二次和第三次执行第二次循环时分母在第二次循环的最后一次迭代中发生了变化,无需声明在第 63 行这样做。

任何帮助将不胜感激,因为稍后在同一个函数中,我将需要这些值来执行其他任务。

提前感谢您的时间!

解决方法

numeroGrupos 被初始化为 4 但您的 gammaResults 数组的大小为 3,因此您正在覆盖内存,即 UB(在您的情况下,它正在修改您的变量)。

gammaResults[3][numeroComponentes] 更改为 gammaResults[numeroGrupos][numeroComponentes]

,

@MikeCAT 建议 Xmi[j][i] 将超出范围,除非 numeroComponentes == numeroGrupos,实际上使 numeroComponentes == numeroGrupos 不能解决问题,但超出范围的建议在正确的方向来解决它。我已将 numeroGrupos 声明为 4 并将 numeroComponentes 声明为 3 并且第 63 行中的语句指示程序修改循环中的元素 Xmi[j][i]

    for (int i=0; i<numeroComponentes; i++) {
        for (int j=0; j<numeroGrupos; j++) {
            ri[i]=ri[i]+RQParameters[j][0]*gruposPorComponente[j][i];
            qi[i]=qi[i]+RQParameters[j][1]*gruposPorComponente[j][i];
            sumaGrupos[i]=sumaGrupos[i]+gruposPorComponente[j][i];
        }
        printf("denominator %f\t",sumaGrupos[i]);
        printf("\n");
        for (int j=0; j<numeroGrupos; j++) {
            printf("numerator before %f\t",gruposPorComponente[i][j]);
            printf("denominator before %f\t",sumaGrupos[i]);
            Xmi[j][i] = gruposPorComponente[j][i]/sumaGrupos[i];
            printf("numerator after %f\t",gruposPorComponente[i][j]);
            printf("denominator after %f\t",sumaGrupos[i]);
            printf("\n");
            suma_XmiTetami[i] = suma_XmiTetami[i] + Xmi[j][i]*RQParameters[j][1];
        }
    }

当第二个循环试图修改 Xmi 的元素时确实存在问题,因为 Xm[i][j] 将超出范围,该语句在某些迭代中指示 Xm[i][j]存储在 sumaGrupos 已经占用的内存地址中,该地址存储了除法的分母。

该问题已解决,只需更改第 43 行 Xmi 中的 double Xmi[numeroComponentes][numeroGrupos]={0}; 声明,该声明将维度反转为 double Xmi[numeroGrupos][numeroComponentes]={0};。正如我在对我的问题的评论中所建议的那样,将 Xm[i][j] 更改为 Xm[j][i] 也可以解决该问题,但这并不是真正的解决方案,尽管它会避免访问 sumaGrupos 已经采用的地址。

犯这样的错误对我来说很有教育意义,因为我发现在 c 中的数组编程中访问地址超出范围的危险,正如这篇文章How dangerous is it to access an array out of bounds?所建议的,你甚至可能损坏你的机器或在不知不觉中将人们置于危险之中。