将变量引用分配给指针会导致意外行为

时间:2017-10-17 19:42:24

标签: c pointers

我正在编写一个C程序来计算Spearman系数。它工作正常,但当我使用

*spearmanCoefficient = coeff;我得到了这个输出:Spearman: 0.01

当我使用

spearmanCoefficient = &coeff;我得到了这个输出:Spearman: 15707109983512927750860237824432537600.00

但是,correlationFlag = &corrFlag;为我提供了正确的输出。

如果我理解正确,第一个语句将变量coeff的值赋给指针spearmanCoefficient的值,第二个语句将变量coeff的地址赋给指针spearmanCoefficient,它应该产生相同的输出,但输出表明第二个语句引用变量​​的地址而不是它的值。

任何人都可以解释为什么会这样吗?谢谢。

源代码:

#include <stdio.h>
#include <math.h>

_Bool Correlate (int size, float arrayOne[], float arrayTwo[], float *spearmanCoefficient, float *correlationFlag)
{
    if (size > 0) {
        float sumOne = 0.0f;
        float sumTwo = 0.0f;
        for (int i = 0; i < size; i++) {
            sumOne = sumOne + arrayOne[i];
            sumTwo = sumTwo + arrayTwo[i];
        }
        float meanOne = sumOne / (float)size;
        float meanTwo = sumTwo / (float)size;

        float varianceOne = 0.0f, varianceTwo = 0.0f;
        for (int i = 0; i < size; i++) {
            sumOne = sumOne + pow((arrayOne[i] - meanOne), 2);
            sumTwo = sumTwo + pow((arrayTwo[i] - meanTwo), 2); 
        }
        varianceOne = sumOne / (float)size;
        varianceTwo = sumTwo / (float)size;
        float coeff = 0.0f;
        float corrFlag = 0.0f;

        for (int i = 0; i < size; i++) {
            coeff = coeff + (((arrayOne[i] - meanOne) * (arrayTwo[i] - meanTwo)) / (size * sqrt(varianceOne * varianceTwo)));
        }
        spearmanCoefficient = &coeff;

        if (coeff >= 0.9 && coeff <= 1.0) {
            corrFlag = 1.0;
        } else if (coeff >= -1.0 && coeff <= -0.9) {
            corrFlag = -1.0;
        } else {
            corrFlag = 0.0;
        }
        correlationFlag = &corrFlag;
        return 1;
    }
    else {
        return 0;
    }
}

int main() {
    float arrayOne[10] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};
    float arrayTwo[10] = {4.0, 6.0, 9.0, 10.0, 2.0, 3.0, 5.0, 5.0, 6.0, 8.0};
    int size = 10;
    float *spearmanCoefficient;
    float *correlationFlag;
    _Bool var = Correlate(size, arrayOne, arrayTwo, spearmanCoefficient, correlationFlag);
    printf("Spearman: %.2f\n", *spearmanCoefficient);
    printf("Flag: %.2f\n", *correlationFlag);
    return 0;
}

2 个答案:

答案 0 :(得分:1)

  

如果我理解正确,第一个语句会赋值   变量coeff到指针spearmanCoefficient

的值

第一个语句*spearmanCoefficient = coeff;将变量coeff的值赋给指针spearmanCoefficient指向的对象。这样做是基于事实上指向某个对象的指针;如果没有,则行为未定义。

  

和   第二个语句将变量coeff的地址分配给   指针spearmanCoefficient

第二个语句spearmanCoefficient = &coeff;确实将变量coeff的地址分配给指针变量spearmanCoefficient

  

应该导致相同的输出但是   输出表明第二个语句引用了   变量的地址而不是它的值。

这两个语句执行不同的操作。它们具有相关但不同的效果,因此它们在程序中是否可以互换取决于程序的其余部分。通常在这种情况下,您使用的变体很重要。

事实证明,这些替代方案的对于编写的其余程序都是正确的。您似乎试图通过指针参数从函数返回Spearman系数和相关标志。在这种情况下,您需要了解在C中,所有程序参数都按值传递。这包括指针类型的参数,这就是我们想要通过参数返回值的原因,该参数需要是一个指针。

您的计划提供了很好的说明。您的Correlate()函数会收到spearmanCoefficient类型的correlationFlagfloat *个参数。这些是调用者指针的副本。您对功能副本所做的更改不会被来电者的原件反映出来。因此,当然,您可以指定spearmanCoeff = &coeff,并且可以使用该指定值和函数,但调用者将看不到结果。

但是,指针在函数中复制指向调用者原始指针所指向的相同内容(如果有的话)。您可以通过指针修改该内容:*spearmanCoeff = coeff。调用者会看到它的效果,但是你的情况有一个问题:主程序没有设置原始的spearmanCoefficientcorrelationFlag指针指向任何东西!因此,当Correlate()取消引用这些指针时,会产生未定义的行为。 可以似乎是您想要或期望的行为,正如您在correlationFlag所声称的那样,但您不能依赖它。

你似乎陷入了一个共同陷阱。缺乏经验的C程序员似乎经常认为当函数需要指针类型的参数时,正确的做法是声明该类型的变量,并传递其值。有时 是正确的做法,但在这种情况下你必须首先分配一个值。然而,很常见的是,正确的做法是声明指向类型的对象,并传递其地址:

int main() {
    float arrayOne[10] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};
    float arrayTwo[10] = {4.0, 6.0, 9.0, 10.0, 2.0, 3.0, 5.0, 5.0, 6.0, 8.0};
    int size = 10;
    float spearmanCoefficient;
    float correlationFlag;
    _Bool var = Correlate(size, arrayOne, arrayTwo, &spearmanCoefficient,
            &correlationFlag);
    printf("Spearman: %.2f\n", spearmanCoefficient);
    printf("Flag: %.2f\n", correlationFlag);
    return 0;
}

这与执行第一类任务的功能有关,而不是第二类。我发现我仍然没有初始化spearmanCoefficientcorrelationFlag变量。这是可以接受的,因为通过我传递的参数,我可以依赖Correlate()main()使用这些变量的值之前为这些变量赋值(通过我传递的指针)。如果我不能依赖它或者不想这样做,那么初始化这些变量或者在调用之前为它们赋值是明智的。

答案 1 :(得分:0)

使用此代码:

#include <stdio.h>
#include <math.h>

_Bool Correlate (int size, float arrayOne[], float arrayTwo[], float *spearmanCoefficient, float *correlationFlag)
{
    if (size > 0) {
        float sumOne = 0.0f;
        float sumTwo = 0.0f;
        for (int i = 0; i < size; i++) {
            sumOne = sumOne + arrayOne[i];
            sumTwo = sumTwo + arrayTwo[i];
        }
        float meanOne = sumOne / (float)size;
        float meanTwo = sumTwo / (float)size;

        float varianceOne = 0.0f, varianceTwo = 0.0f;
        for (int i = 0; i < size; i++) {
            sumOne = sumOne + pow((arrayOne[i] - meanOne), 2);
            sumTwo = sumTwo + pow((arrayTwo[i] - meanTwo), 2); 
        }
        varianceOne = sumOne / (float)size;
        varianceTwo = sumTwo / (float)size;
        float coeff = 0.0f;
        float corrFlag = 0.0f;

        for (int i = 0; i < size; i++) {
            coeff = coeff + (((arrayOne[i] - meanOne) * (arrayTwo[i] - meanTwo)) / (size * sqrt(varianceOne * varianceTwo)));
        }
        *spearmanCoefficient = coeff;

        if (coeff >= 0.9 && coeff <= 1.0) {
            corrFlag = 1.0;
        } else if (coeff >= -1.0 && coeff <= -0.9) {
            corrFlag = -1.0;
        } else {
            corrFlag = 0.0;
        }
        *correlationFlag = corrFlag;
        return 1;
    }
    else {
        return 0;
    }
}

int main() {
    float arrayOne[10] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};
    float arrayTwo[10] = {4.0, 6.0, 9.0, 10.0, 2.0, 3.0, 5.0, 5.0, 6.0, 8.0};
    int size = 10;
    float spearmanCoefficient;
    float correlationFlag;
    _Bool var = Correlate(size, arrayOne, arrayTwo, &spearmanCoefficient, &correlationFlag);
    printf("Spearman: %.2f\n", spearmanCoefficient);
    printf("Flag: %.2f\n", correlationFlag);
    return 0;
}