Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Problème fonction realloc


Sujet :

C

  1. #1
    Candidat au Club
    Femme Profil pro
    Étudiant
    Inscrit en
    octobre 2019
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 26
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : octobre 2019
    Messages : 1
    Points : 2
    Points
    2
    Par défaut Problème fonction realloc
    Hello !

    J'apprends les pointeurs et je viens d'apprendre quelques notions sur l'allocation dynamique également.
    Je réalise un exercice pour lequel j'ai créé une structure, au sein de laquelle se trouve un tableau de pointeurs vers des chaines de caractères. Le nombre de chaines de caractères pouvant varier, je dois pouvoir rajouter de manière dynamique des pointeurs dans mon tableau (je le fais dans une fonction et non pas dans le main, en passant à la cette fonction le pointeur de ma structure). J'essaie d'utiliser la fonction realloc mais sans succès : le programme plante et affiche le message "exe has triggered a breakpoint" (à la ligne 30 dans le code ci-dessous)...
    Une bonne âme pourrait-elle m'expliquer mon erreur ? J'ai dû mal comprendre certaines notions...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
     
     
    void AjoutMessage(struct etGMessage *pGMessage)
    {
    	/************************************************************************************************/
    	/* sMessage : variable dans laquelle on stockera le message du programme utilisateur.           */
    	/* dLongueurMessage : variable qui permettra de stocker la longueur de la chaine de caractères. */
    	/* **pPointeurTableau : double pointeur pointant vers l'entièreté du tableau de pointeurs.      */
    	/************************************************************************************************/
     
    	char sMessage[100];
    	int dLongueurMessage;
    	char **pPointeurTableau = pGMessage->tMessages;
     
    	/*******************************************************************************************/
    	/* D'abord, on regarde s'il reste de la place dans le gestionnaire de messages.            */
    	/* Si le gestionnaire est plein, il faut agrandir la zone mémoire du tableau de pointeurs. */
    	/*******************************************************************************************/
     
    	if (pGMessage->dNextFreeCell == pGMessage->dTableSize)
    	{
    		/******************************************************************************************************************/
    		/* On incrémente la variable contenant la taille du tableau de pointeurs.                                         */
    		/* On réalloue au double pointeur pointant vers le tableau de pointeurs de la mémoire :                           */
    		/* on multiplie par la nouvelle taille du tableau de pointeurs le nombre de bytes que prend un pointeur sur char. */
    		/******************************************************************************************************************/
     
    		pGMessage->dTableSize++;
     
    		pPointeurTableau = (char**)realloc(pPointeurTableau, pGMessage->dTableSize * sizeof(char*));
    	}
     
    	/************************************************/
    	/* On réceptionne ensuite le message à stocker. */
    	/************************************************/
     
    	printf("Message a ajouter au gestionnaire :\n");
    	gets_s(sMessage);
     
    	/*********************************************************/
    	/* On calcule la longueur de cette chaine de caractères. */
    	/*********************************************************/
     
    	dLongueurMessage = strlen(sMessage);
     
    	/***************************************************************************************************************/
    	/* On alloue de manière dynamique de la mémoire (taille = longueur de la chaine de caractères + 1 pour le \0.) */
    	/* On spécifie avant la fonction malloc que c'est un pointeur char*.                                           */
    	/* Le sizeof(char) est omis car il est égal à 1.                                                               */
    	/***************************************************************************************************************/
     
    	pGMessage->tMessages[pGMessage->dNextFreeCell] = (char*)malloc(dLongueurMessage + 1);
     
    	/**********************************************************************************/
    	/* On copie notre chaine de caractères dans cet espace mémoire nouvellement créé. */
    	/**********************************************************************************/
     
    	strcpy(pGMessage->tMessages[pGMessage->dNextFreeCell], sMessage);
     
    	/*************************************************************************************/
    	/* On incrément l'index pointant vers le prochain emplacement libre du gestionnaire. */
    	/*************************************************************************************/
     
    	pGMessage->dNextFreeCell++;
    }
    Apparemment, je devrais vérifier que la fonction realloc a bien fonctionné (elle ne ramène pas la valeur "NULL"). Mais ici je ne sais même pas le vérifier, étant donné que la fonction plante...

    Merci à ceux qui pourront m'aider !

  2. #2
    Expert éminent
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    juillet 2013
    Messages
    3 052
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : juillet 2013
    Messages : 3 052
    Points : 6 745
    Points
    6 745
    Par défaut
    La fonction realloc a un comportement particulier (<- lien cplusplus en anglais)

    Regarde le lien (les explications et l'exemple).
    En gros, si le retour n'est pas NULL c'est l'adresse du nouveau bloc et donc tu peux écraser le pointeur courant (il est invalide) et si le retour est NULL alors il y a un problème et il faut désallouer le pointeur courant.

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    7 567
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 7 567
    Points : 21 556
    Points
    21 556
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par SophieW Voir le message
    Une bonne âme pourrait-elle m'expliquer mon erreur ? J'ai dû mal comprendre certaines notions...
    Tu as commis une erreur qui s'étale sur 3 instructions
    1) tu commences par récupérer pGMessage->tMessages (qui est donc un liste de strings) dans une variable de travail "pointeurTableau"
    2) tu réalloues plus de mémoire à "pointeurTableau". A ce moment là, l'adresse est susceptible de changer totalement (si par exemple la zone qui était allouée était enclavée et ne peut pas grandir, realloc va allouer totalement ailleurs)
    3) tu continues à travailler dans pGMessage->tMessages. Mais là, il est possible qu'il n'y ait plus de lien entre "pGMessage->tMessages" et "pointeurTableau". Donc tu continues à remplir l'ancienne adresse qui n'est peut-être plus valide.

    Il faut supprimer l'instruction pointeurTableau=pGMessage->tMessages puis remplacer la zone de realloc par
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    pPointeurTableau = realloc(pGMessage->tMessages, pGMessage->dTableSize * sizeof(char*));              // Le cast est inutile
    if (pointeurTableau == NULL) {
         // Ici il faut libérer toutes les strings allouées individuellement
         ...
     
         // Libération liste de strings
         free(pGMessage->tMessages);
        return NULL;
    }
    pGMessage->tMessages=pointeurTableau;

    Accessoirement réallouer de 1 en 1 n'est pas optimum. Ce qu'on fait plutôt c'est
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    récupérer donnée
    si taille utilisée == taille allouée faire
         agrandir taille allouée de N
         réallouer tableau à la taille allouée
         tester réallocation
    fin si
    stocker donnée dans tableau[taille_utilisée]
    taille_utilisée++
    Et ça fonctionne même à la toute première allocation car à ce moment là, "taille_utilisée"="taille_allouée"=0. Et si "tableau" vaut alors NULL, realloc se comporte comme malloc.

    Citation Envoyé par foetus Voir le message
    En gros, si le retour n'est pas NULL c'est l'adresse du nouveau bloc et donc tu peux écraser le pointeur courant (il est invalide) et si le retour est NULL alors il y a un problème et il faut désallouer le pointeur courant.
    Exact. Mais ce n'est pas ça qui fait planter son truc. En gros, même si ce n'est pas recommandé, écrire adr=realloc(adr, nouvelle taille) reste fonctionnel quand realloc() ne renvoie pas NULL
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

Discussions similaires

  1. Problème Affectation fonction realloc
    Par eclectique_95470 dans le forum C
    Réponses: 7
    Dernier message: 21/12/2010, 21h51
  2. Réponses: 13
    Dernier message: 21/03/2009, 21h49
  3. Réponses: 4
    Dernier message: 10/03/2008, 04h59
  4. Réponses: 2
    Dernier message: 20/08/2004, 18h10
  5. Re-problème avec realloc() (désolé)
    Par Yabo dans le forum C
    Réponses: 8
    Dernier message: 30/07/2003, 23h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo