2017-10-17 24 views
0

我正在編寫一個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

在'main'沒有指向任何地方這些指針。 – Kevin

+1

您的函數不會更新指針,因爲它們是按值傳遞的。如果指針已更新,它仍然無法工作,因爲它們會指向不再存在的局部變量。 –

回答

1

如果我正確理解,第一條語句的 可變coeff值賦給指針spearmanCoefficient

的第一個語句的值,*spearmanCoefficient = coeff; ,將變量coeff的值分配給指針spearmanCoefficient指向的對象。這樣做是基於事實上指向某個對象的指針;如果沒有,那麼行爲是不確定的。

和 第二條語句變量coeff的地址分配給 指針spearmanCoefficient

第二條語句,spearmanCoefficient = &coeff;,確實可變coeff的地址賦給指針變量spearmanCoefficient

這將導致相同的輸出,但 輸出表明第二語句引用變量​​的 地址,而不是它的值。

這兩個語句執行不同的操作。它們具有相關但不同的效果,因此它們在程序中是否可互換取決於程序的其餘部分。通常在這種情況下,您使用哪種變體確實是的問題。

事實證明,這些替代方案中的既不是對於程序的其餘部分都是正確的。你似乎試圖通過指針參數從你的函數返回斯皮爾曼係數和相關標誌。在這種情況下,您需要了解在C中,所有程序參數均以值通過。這包括指針類型的參數,這就是如果我們想通過參數返回一個值的原因,那個參數需要是一個指針。

您的程序提供了一個很好的例子。您的Correlate()函數接收參數spearmanCoefficientcorrelationFlag,這兩個類型都是float *。這些是調用者指針的副本。您對功能副本所做的更改不會反映在主叫方的原件中。因此,當然,您可以指定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。這是可以接受的,因爲通過我傳遞的參數,在main()使用這些變量的值之前,我可以依靠Correlate()爲這些變量賦值(通過我傳遞的指針)。如果我不能依賴或者不想這樣做,那麼初始化這些變量或者在調用之前爲其分配值是明智的。

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; 
} 
相關問題