2015-04-21 1 views
1

Je crée une liste liée qui contient des noeuds avec le "dataItem" d'un pointeur vide. Le but de ceci est de permettre au nœud de contenir n'importe quel type de données. Cependant, je suis incapable d'accéder aux données du pointeur vide, même lorsque ces données sont castées au type correct.Impossible d'accéder au pointeur de vidage

Mon code ressemble à ceci:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
typedef struct Student 
{ 
    char stuName[51]; 
    char stuMajor[5]; 
    double GPA; 
    char stuID[10]; 
}student; 

typedef struct Node 
{ 
    union{ 
     void *dataPtr; 
     int countr; 
    }dataItem; 
    int link; 
    struct Node* next; 
}node; 
void readData(struct Node *); 

void main(){ 
    node head; 
    node temp; 
    readData(&temp); 
    student *ptr = (student *)(temp.dataItem.dataPtr); 
    printf("%s %d", ptr->stuName, ptr->GPA);//breaks here because unable to access memory 
} 

void readData(struct Node *link) 
{ 
    link = (node *)malloc(sizeof(node)); 
    student *ptr = (student *)malloc(sizeof(struct Student)); 
    printf("enter the student name : "); 
    fflush(stdin); 
    scanf("%[^\n]", ptr->stuName); 
    printf("enter the student's major : "); 
    fflush(stdin); 
    scanf("%[^\n]", ptr->stuMajor); 
    printf("enter the student GPA : "); 
    scanf("%lf", &(ptr->GPA)); 
    printf("enter the student ID : "); 
    fflush(stdin); 
    scanf("%[^\n]", ptr->stuID); 
    link->dataItem.dataPtr = ptr; 
} 

Je sais que j'ai certainement un pointeur mal quelque part, je ne suis pas sûr comment. J'ai également le noeud dans ma fonction readData point à une nouvelle malloc de noeud parce que je veux un nouveau noeud chaque fois que readData est appelé quand j'implémente la liste liée plus loin.

+1

Ici 'student * ptr = (student *) (temp.dataItem.dataPtr);' la distribution est complètement inutile. Ainsi que ici 'link = (noeud *) malloc (sizeof (noeud));'. Et ainsi de suite ... Et ce 'fflush (stdin);' est un comportement indéfini, vous ne devriez jamais 'fflush()' un flux d'entrée. Avez-vous inclus des en-têtes? et 'main()' renvoie une valeur, 'int'. –

Répondre

5

Votre code est très cassé,

  1. Vous n'avez pas inclus un fichier d'en-tête, vous avez besoin d'au moins stdlib.h pour malloc() et stdio.h pour printf() et scanf().

  2. Votre définition main() est erronée, car main() doit renvoyer int.

  3. Vous fflush(stdin) qui est un comportement indéfini.

  4. Vous ignorez la valeur de retour de scanf().

  5. Vous supposez que malloc() renvoie toujours un pointeur valide.

  6. Vous avez appelé readData() qui n'est pas encore déclaré.

Mais le plus important erreur, est que vous avez passé l'adresse « node temp-readData() et vous malloc() Éd, mais vous ne retournez pas un pointeur vers elle, perdant ainsi toutes les modifications apportées à l'intérieur readData() qui sera ne fonctionne pas de toute façon car il n'est pas déclaré au moment où vous l'appelez.

je fixe votre code, parce que je sais que vous ne l'avez pas aimé ma réponse, mais vérifier les correctifs qui sont liés à la réponse, et maintenant il fonctionne comme je m'y attendais

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

typedef struct Student 
{ 
    char stuName[51]; 
    char stuMajor[5]; 
    double GPA; 
    char stuID[10]; 
} student; 

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

void readData(struct Node **link); 


int main() 
{ 
    node *head; 
    student *ptr; 

    readData(&head); 

    ptr = head->dataItem.dataPtr; 
    if (ptr != NULL) 
     printf("%s\t%g", ptr->stuName, ptr->GPA); 
    return 0; 
} 

void readData(struct Node **link) 
{ 
    student *ptr; 
    if (link == NULL) 
     return; 
    *link = malloc(sizeof(node)); 
    if (*link == NULL) 
     return; 
    memset(*link, 0, sizeof(node)); 

    ptr = malloc(sizeof(struct Student)); 
    if (ptr == NULL) 
     return; 
    printf("enter the student name : "); 
    if (scanf("%50[^\n]%*c", ptr->stuName) != 1) 
     ptr->stuName[0] = '\0'; 

    printf("enter the student's major : "); 
    if (scanf("%4[^\n]%*c", ptr->stuMajor) != 1) 
     ptr->stuMajor[0] = '\0'; 

    printf("enter the student GPA : "); 
    if (scanf("%lf%*c", &(ptr->GPA)) != 1) 
     ptr->GPA = 0; 

    printf("enter the student ID : "); 
    if (scanf("%9[^\n]%*c", ptr->stuID) != 1) 
     ptr->stuID[0] = 0; 

    (*link)->dataItem.dataPtr = ptr; 
} 

J'ai aussi ajouté certains correctifs de sécurité à scanf() ajoutant le modificateur de longueur pour empêcher le débordement de tampon, et également supprimer le '\n' arrière avec spécificateur "%*c", cela ne fonctionnera pas si plusieurs espaces suivent la valeur, mais vous pouvez le tester en attendant simplement en appuyant sur Entrée/Retour, si vous voulez une entrée plus sophistiquée, vous devez utiliser autre chose au lieu de scanf().

+0

1. ces fichiers d'en-tête sont inclus, je pensais qu'il était évident qu'ils seraient 2. main ne doit pas retourner int, et ne retournera un avertissement que si ce n'est pas – beckah

+2

Ce n'est pas évident et c'est une cause fréquente de problèmes . Puisque votre compilateur ne s'est pas plaint de 'readData()', il est raisonnable de penser que vous n'avez pas inclus les fichiers d'en-tête. La déclaration de fonction implicite est votre ennemi, et vous semblez l'ignorer parce que vous n'avez pas déclaré 'readData()' avant de l'appeler. La même chose se produira si vous ne parvenez pas à inclure les en-têtes, sans que les avertissements du compilateur ne soient activés, le code sera compilé sans aucun problème, ce qui ne signifiera pas qu'il n'y a pas de problèmes. –

+0

@beckah 'main()' n'a pas à retourner explicitement une valeur, car c'est une exception aux règles habituelles du compilateur - il peut être par défaut. Mais 'main()' doit être de type 'int' sauf pour certaines applications embarquées, où il ne retourne pas. –

2

Ce:

void readData(struct Node *link) 
{ 
    link = (node *)malloc(sizeof(node)); 

Vous jetez la valeur du paramètre link qui a été passé, l'attribution à la place une nouvelle allocation par malloc. C'est votre problème le plus important, je pense. Une solution simple serait de supprimer la ligne effectuant le malloc.

+0

Il est en effet, et la création d'un noeud d'une liste liée qui n'est pas un pointeur, n'a pas beaucoup de sens. –

0

Vous souhaitez transmettre un pointeur à un pointeur (ou l'adresse d'un pointeur) à un nœud de la fonction readData(). readData alloue un nouveau noeud et le remplit; ce qui se passe dans votre code est que readData() obtient un copy de l'adresse de temp, écrase la copie de cette adresse avec une nouvelle adresse, celle obtenue de malloc (qui est invisible pour le code appelant dans main()) puis remplit cet objet mallocé. Au retour de readData l'objet mallocé est inaccessible.

Qu'est-ce que vous vouliez faire est la suivante:

void main(){ 
    node head; 
    node *tempAddr; // pointer 
    readData(&tempAddr); // pass address of that pointer 

puis utilisez *tempAddr dans le principal lieu de temp. Se détendre se plaindrait que vous ne devriez pas lancer le résultat de malloc, mais je pense que c'est bien. Je ne me soucie pas non plus de la valeur de retour de main, ou de ses arguments.

+0

"Vous voulez passer un pointeur vers un pointeur (ou l'adresse d'un pointeur) vers un noeud à la fonction readData()" - c'est une interprétation possible; une autre est que la signature 'readData' est correcte, et que l'appelant doit allouer le noeud. – davmac

+0

@davmac Eh bien, le fait que l'OP * attribue * le noeud dans 'readData' supporte fortement mon interprétation, je pense ;-) –

+0

Je pense que le fait que l'OP passe dans un noeud déjà alloué, et que le type de paramètre est 'struct Node *', sont également forts dans le soutien de l'interprétation alternative. – davmac