2015-04-22 1 views
1

J'ai un tableau de structures appelé node s. Chaque noeud contient un champ d'un pointeur vide.L'impression (Char *) (Void *) fonctionne dans le programme principal mais ne fonctionne pas

Dans une fonction, je prends le nœud spécifique et affecte le pointeur vide à une chaîne, cette chaîne contenant le résultat d'une décimale qui a été convertie en binaire. Le problème est que l'accès et l'impression de ce pointeur de void cast en char * fonctionne correctement dans la fonction pour assigner le void * à un nouveau char * AND imprime bien en revenant à la fonction principale. Cependant, il ne s'imprime pas correctement lorsque j'essaie de l'imprimer dans une fonction séparée qui prend le nœud [] et l'index du tableau en arguments.

Pour aider à éclairer la confusion c'est la version simplifiée de mon programme:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define listSize 100 

typedef struct Node 
{ 
    union{ 
     void *dataPtr; 
     int countr; 
    }dataItem; 
    int link; 
}node; 

void loadData(node*); 
void printFunc(node[], int); 

void main() 
{ 
    struct Node Stack[listSize]; 

    loadData(&Stack[0]); 

    //This prints fine 
    char * temp; 
    temp = (char*)(Stack[0].dataItem.dataPtr); 
    printf("\nMain(): Stack[empty].dataItem.dataPtr = %s\n", temp); 


    printFunc(Stack, 0); 

} 

void loadData(node* link){ 
    char string[220]; 

    int n, c, k, i; 

    printf("Enter an integer: "); 
    scanf("%d", &n); 

    i = 0; 

    for (c = 31; c >= 0; c--) 
    { 
     k = n >> c; 

     if (k & 1){ 
      string[i] = '1'; 
      i++; 
     } 
     else{ 
      string[i] = '0'; 
      i++; 
     } 
     if (c == 0){ string[i] = '\0'; }//end the string 
    } 

    link->dataItem.dataPtr = &string; 

    //This prints fine: 
    printf("\nLoadData(): link->dataItem.dataPtr is now %s\n", (char *)(link->dataItem.dataPtr)); 
} 


void printFunc(node Stack[], int newLink){ 

    //This does not work! 
    char* temp; 
    temp = (char*)(Stack[newLink].dataItem.dataPtr); 
    printf("\npush(): Stack[newLink].dataItem.dataPtr %s\n", temp); 
} 

Sortie: Output of program

Je compile également les dans Visual Studios 2012. Je sais que parfois des pointeurs dans GCC à la Le compilateur Microsoft C peut être un peu différent.

Qu'est-ce que j'écris qui empêche le programme d'imprimer le message void * cast comme char * dans la fonction printFunc?

+3

'lien-> dataItem.dataPtr = & string;' - cela ne fonctionne pas. Tout d'abord, vous n'avez pas besoin de '&', car le tableau local se désintègre en un pointeur. Deuxièmement, et plus important encore, vous assignez un tableau local à un pointeur à utiliser en dehors de sa portée. C'est un comportement indéfini. –

Répondre

1

C'est ce qui se passe dans votre code:

Comme vous appelez la fonction LoadData, il alloue string[220] sur la pile. La pile ressemble alors à ceci:

[main variables] [LoadData variables, including string[220]] <-- HEAD 

Ensuite, les données de chargement se terminent. À sa sortie, il renvoie le pointeur de la pile. A cette époque, votre pile ressemble à ceci:

[main variables] <-- HEAD [LoadData variables, including string[220]] 

Notez que dans votre cas string est toujours techniquement là, il peut être lu et accessible, mais cela est purement par hasard et dépend de votre mise en œuvre de complier. Un autre compilateur pourrait l'avoir immédiatement effacé, ou l'avoir optimisé d'une autre manière. Dès qu'une fonction se termine, il ne devrait plus y avoir de pointeurs pointant vers les variables allouées sur la pile! Votre code viole ceci, en laissant un pointeur sur la pile allouée string. A ce moment, votre code est déjà dans la zone de danger! Au moment où vous accédez à ce pointeur, votre code peut tomber en panne, votre ordinateur peut prendre feu, ou le monde peut cesser d'exister.

Mais dans votre cas, string est toujours accessible, alors que vous l'imprimez depuis main, il semble être imprimé correctement. Cela vous donne l'illusion que tout va bien. L'illusion disparaît lorsque vous appelez le printFunc, car maintenant il occupera l'espace de pile où se trouvait string!

[main variables] [printFunc variables] <-- HEAD 

Notez que le string est maintenant disparu! Mais votre variable Stack pointe toujours vers cette mémoire, qui contient maintenant des ordures!

Comment y remédier? Eh bien, si vous prévoyez de revenir quelque chose de la fonction, vous devez soit allouer chaîne pour que, du côté appelant:

int main { 
    ... 
    char string[220]; 
    LoadData(&Stack[0], string); // and make LoadData use the argument string instead of creating its own 
    ... 
} 

ou faire LoadData affecter la chaîne sur le tas:

char* LoadData (...) { 
    char* string = malloc(220); 
    ... 
} 

En auquel cas ne pas oublier de le désaffecter dans main plus tard:

int main() { 
    loadData(&Stack[0]); 
    ... 
    free(Stack[0].dataItem.dataPtr); 
} 
1

Vous assignez la dataPtr à une chaîne qui est déclarée sur la pile sur cette ligne:

link->dataItem.dataPtr = &string; 

Une fois que vous êtes hors de portée vous avez un comportement non défini. Vous devez allouer de la mémoire pour la chaîne sur le tas.

char *string = malloc(220); 

... 

//then assign it directly 
link->dataItem.dataPtr = string; 

Vous aurez également besoin d'une fonction pour libérer toutes vos données lorsque vous avez terminé.

+0

... et 'strcpy()', ou simplement utiliser quelque chose comme ['strdup()'] (http://pubs.opengroup.org/onlinepubs/009695399/functions/strdup.html) si amiable. – WhozCraig