2017-10-17 12 views
0

J'écrivais un programme C pour calculer le coefficient de Spearman. Il fonctionne très bien, mais quand je l'utiliseAffecter la référence de la variable au pointeur entraîne un comportement inattendu

*spearmanCoefficient = coeff; je reçois cette sortie: Spearman: 0.01

et quand j'utilise

spearmanCoefficient = &coeff; je reçois cette sortie: Spearman: 15707109983512927750860237824432537600.00

Cependant, correlationFlag = &corrFlag; me donne la sortie correcte.

Si je comprends bien, la première instruction affecte la valeur de la coeff variable à la valeur du pointeur spearmanCoefficient et la deuxième instruction attribue l'adresse du coeff variable au pointeur spearmanCoefficient qui devrait aboutir à la même sortie, mais la La sortie suggère que la deuxième déclaration fait référence à l'adresse de la variable et non à sa valeur.

Quelqu'un peut-il expliquer pourquoi cela se produit? Je vous remercie.

code source:

#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

Ces pointeurs 'main' ne pointent pas vers nulle part. – Kevin

+1

Votre fonction ne met pas à jour les pointeurs car ils sont passés par valeur. Et si les pointeurs étaient mis à jour, cela ne fonctionnerait pas car ils pointeraient vers des variables locales qui n'existent plus. –

Répondre

1

Si je comprends bien, la première instruction affecte la valeur de la coeff variable à la valeur du pointeur spearmanCoefficient

La première déclaration, *spearmanCoefficient = coeff; , affecte la valeur de la variable coeff à l'objet auquel pointe le pointeur spearmanCoefficient. Faire ceci est basé sur le pointeur qui pointe en fait sur un objet; si ce n'est pas le cas, le comportement n'est pas défini.

et la deuxième instruction attribue l'adresse du coeff variable au pointeur spearmanCoefficient

La deuxième déclaration, spearmanCoefficient = &coeff;, n'attribuer l'adresse de la variable coeff à la variable pointeur spearmanCoefficient.

qui devrait aboutir à la même sortie, mais la sortie suggère que la deuxième déclaration fait référence à l'adresse de la variable et non sa valeur.

Les deux instructions exécutent des opérations distinctes. Ils ont des effets liés, mais différents, donc s'ils sont interchangeables dans votre programme dépend du reste du programme. Habituellement dans de telles situations, quelle variation vous utilisez fait question.

Comme il s'avère, ni de ces alternatives est correcte pour le reste du programme comme écrit. Vous semblez essayer de renvoyer le coefficient Spearman et l'indicateur de corrélation de votre fonction via des arguments de pointeur. Dans ce cas, vous devez comprendre qu'en C, tous les arguments du programme sont passés par la valeur.Cela inclut les arguments de type pointeur, et c'est la raison pour laquelle si nous voulons renvoyer une valeur via un argument, cet argument doit être un pointeur.

Votre programme fournit une bonne illustration. Votre fonction Correlate() reçoit les arguments spearmanCoefficient et correlationFlag, tous les deux de type float *. Ce sont copies des pointeurs de l'appelant. Les modifications apportées aux copies de la fonction ne sont pas reflétées par les originaux de l'appelant. Ainsi, bien sûr, vous pouvez affecter spearmanCoeff = &coeff, et vous pouvez utiliser cette valeur assignée avec la fonction, mais l'appelant ne verra pas le résultat. CEPENDANT, le pointeur copie dans la fonction point à la même chose (si quelque chose) que les pointeurs d'origine de l'appelant pointent vers. Vous pouvez modifier cette chose via les pointeurs: *spearmanCoeff = coeff. L'appelant verra l'effet de cela, mais il y a un problème dans votre cas: le programme principal ne définit pas ses pointeurs originaux spearmanCoefficient ou correlationFlag pour pointer vers n'importe quoi! Par conséquent, lorsque Correlate() déréferences ces pointeurs, un comportement non défini résulte. Que peut semble être le comportement que vous voulez ou attendez, comme vous le prétendez est le cas avec correlationFlag, mais vous ne pouvez pas compter sur cela.

Vous semblez être tombé dans un piège commun. Les programmeurs C inexpérimentés semblent souvent penser que lorsqu'une fonction veut un argument de type pointeur, la bonne chose à faire est de déclarer une variable de ce type, et de passer sa valeur. Cela est parfois la bonne chose à faire, même si vous devez dans ce cas assigner une valeur en premier. Il est assez fréquent, cependant, que la bonne chose à faire est de déclarer un objet de la pointe à saisir et transmettre son adresse:

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; 
} 

Cela va de pair avec la fonction d'effectuer des missions de votre premier type, non votre deuxième type. Je remarque que je n'initialise toujours pas les variables spearmanCoefficient et correlationFlag. Ceci est acceptable parce que, avec les arguments que je passe, je peux compter sur Correlate() pour affecter des valeurs à ces variables (via les pointeurs que je passe) avant que main() utilise les valeurs de ces variables. Si je ne pouvais pas me fier à cela ou si je ne voulais pas le faire, il serait prudent d'initialiser ces variables, ou sinon de leur assigner des valeurs avant l'appel.

0

Utilisez ce code:

#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; 
}