Erreur malloc [Résolu]

Messages postés
109
Date d'inscription
samedi 3 novembre 2007
Dernière intervention
4 février 2016
-
Bonjour,

Je suis en train d'écrire un programme en c sous VS2010 qui utilise les listes chainées.

J'ai un problème lors d'une allocation mémoire.
Je suis en train d'allouer de la mémoire pour une variable de type la structure suivante :
typedef struct structNoeudCONT
{
 ELEMENT_CONT info;
 struct structNoeudCONT * suivant;
}structNoeudCONT, * NOEUD_CONT;


où ELEMENT_CONT est :
typedef struct
{
 char nom[50];
 char numero[9];
 char email[30];
}CONTACT,*ELEMENT_CONT;

Quand je veux exécuter l'instruction suivante :
NOEUD_CONT temp=  (NOEUD_CONT)malloc ( sizeof(structNoeudCONT));

Je reçoit l'erreur
Unhandled exception at 0x77a6e753 in ProjetSMSV2.exe: 0xC0000374: A heap has been corrupted.
au niveau de la fonction pvBlk = _heap_alloc_dbg_impl(nSize, nBlockUse, szFileName, nLine, errno_tmp); du fichier dbgheap.c.

cette erreur n'arrive que lorsque je veux allouer à partir d'un fichier LSTCON.C qui fait include au fichier.h ou les structure mentionné et la déclaration des fonctions sont définie.
Si je fait appel à cette allocation directement dans le main.c, je ne reçois pas cet exception et l'allocation se fait normalement.

Quelqu'un aurait une idée sur le problème ?
Merci Beaucoup


--
Afficher la suite 

Votre réponse

6 réponses

Messages postés
3830
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
19 novembre 2018
0
Merci
Bonjour.

Difficile à dire, avec si peu d'information. Peux-tu créer un exemple minimaliste (autonome et compilable), reproduisant le problème ?
Je pourrais alors le tester chez moi.

__________________________________________________________________________________________________

Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
Commenter la réponse de cptpingu
Messages postés
109
Date d'inscription
samedi 3 novembre 2007
Dernière intervention
4 février 2016
0
Merci
Bonjour

Merci pour la réponse, en fait c'est un tp pour expliquer la notion de la liste chainée.
J'ai supprimé plusieurs parties et j'ai laissé les fichiers relatifs au bug.
J'ai mis dans le commentaire //Pour_CODE_SOURCE pour expliquer un peu ce qui se passe.
il faut effectuer le programme, choisir menu contact, ensuite ajouter un contact, et là l'exception arrive.
Mais je ne trouve pas comment uploader le code ici :(

--
Commenter la réponse de cs_aymen87
Messages postés
3830
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
19 novembre 2018
0
Merci
Pas besoin d'uploader quoi que ce soit.

Tu colles tout ton code dans un seul fichier (tu vérifies si ça compile). Puis tu copies-colle ici.

__________________________________________________________________________________________________

Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
Commenter la réponse de cptpingu
Messages postés
109
Date d'inscription
samedi 3 novembre 2007
Dernière intervention
4 février 2016
0
Merci
ok ci dessous les fichiers du programme, ça compile correctement sous VS 2010.

Merci Beaucoup :)

Fichier main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "LSTCON.H"
#include "LISTCONPRIM.H"

void afficherMenuPrincipal(LISTE_CONT listContacts);
void afficherMenuContact(LISTE_CONT listContacts);
void ajouterUnContact();
void supprimerUnContact(LISTE_CONT listContacts);

extern int insererlisteCont(LISTE_CONT,ELEMENT_CONT,int); 
extern LISTE_CONT listeContCreer ( void); 
extern int supprimerlisteCont(LISTE_CONT l,int pos);
extern void listeContAfficher (LISTE_CONT l);

void main()
{
 //Création des listes qu'on va utiliser dans tout le programme.
 LISTE_CONT listeDesContat = listeContCreer();

 //Pour_CODE_SOURCE l'allocation de mémoire fonctionne correctement si on fait un appel ici
 listeContEstSaturee (listeDesContat);
 afficherMenuPrincipal(listeDesContat);
}

void afficherMenuContact(LISTE_CONT listContacts)
{
 char choix;

 do
 {
  system("cls");
  printf("\t\t **************************************** \n");
  printf("\t\t **************************************** \n");
  printf("\t\t ********** Gestion de Contact ********** \n");
  printf("\t\t **************************************** \n");
  printf("\t\t **************************************** \n\n");
  printf("\t\t\t Veuillez faire un choix : \n\n");
  printf("\t\t\t 1- Ajouter un Contact : \n");
  printf("\t\t\t 2- Afficher les Contacts : \n");
  printf("\t\t\t 3- Supprimer un contact : \n");
  printf("\t\t\t 4- Afficher le plus contacté : \n");
  printf("\t\t\t 5- Afficher le jamais contacté : \n");
  printf("\t\t\t 6- Retour : \n");
  scanf("%c",&choix);
 }
 while(
  (choix != '1') 
  && (choix != '2') 
  && (choix != '3') 
  && (choix != '4') 
  && (choix != '5')
  && (choix != '6'));

 switch(choix)
 {
  case '1':
   ajouterUnContact(listContacts);
   printf("Operation d'ajout terminée ! Appuyez sur une touche,\n");
   getchar();
   afficherMenuContact(listContacts);
   break;
 
  case '2':
   listeContAfficher(listContacts);
   printf("Operation d'affichage terminée ! Appuyez sur une touche,\n");
   getchar();
   afficherMenuContact(listContacts);
   break;

  case '3':
   supprimerUnContact(listContacts);
   printf("Operation de suppression terminée ! Appuyez sur une touche,\n");
   getchar();
   afficherMenuContact(listContacts);
   break;

  case '4':
  //Afficher le plus contacté
   break;

  case '5':
  //Afficher le jamais contacté
   break;
  case '6':
  afficherMenuPrincipal(listContacts);
   break;
  default:
   break;
 }
}


void afficherMenuPrincipal(LISTE_CONT listContacts)
{
 char choix;

 do
 {
  system("cls");
  printf("********************************************************************* \n");
  printf("********************************************************************* \n");
  printf("********** Application de Gestion de Message et de Contact ********** \n");
  printf("**********   Bienvenue     ********** \n");
  printf("********************************************************************* \n");
  printf("********************************************************************* \n\n");
  printf("\t\t\t Veuillez faire un choix : \n\n");
  printf("\t\t\t 1- Gestion de Contact : \n");
  printf("\t\t\t 2- Gestion de Messages : \n");
  scanf("%c",&choix);
 }while((choix!='1')&&(choix!='2'));

 switch(choix)
 {
 case '1':
  afficherMenuContact(listContacts);
  break;
 
 case '2':
  break;

 default:
  break;
 }
 
}

void ajouterUnContact(LISTE_CONT listContacts)
{
 ELEMENT_CONT contact = elementConcreer();
 printf("Donnez le nom du contact \n");
 scanf("%50s",contact->nom);

 printf("Donnez le numéro du contact \n");
 scanf("%8s",contact->numero);

 printf("Donnez l'email du contact \n");
 scanf("%30s",contact->email);

 //Pour_CODE_SOURCE l'allocation de mémoire ne fonctionne pas si on fait une allocation de mémoire sous cette fonction
 insererlisteCont(listContacts,contact,listContacts->lg+1);

}

void supprimerUnContact(LISTE_CONT listContacts)
{
 int contactIndex;
 printf("Donnez l'index du contact \n");
 scanf("%s",&contactIndex);

 supprimerlisteCont(listContacts,contactIndex);
 
}


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

#include "ELTCONPRIM.H"


ELEMENT_CONT elementConcreer()
{
 ELEMENT_CONT e;
 e = (ELEMENT_CONT)malloc(sizeof(ELEMENT_CONT));
 memset(e->email,0,sizeof(e->email));
 memset(e->nom,0,sizeof(e->nom));
 memset(e->numero,0,sizeof(e->numero));

 return e;

}
void elementCondetruire(ELEMENT_CONT e)
{
 free(e);
}
void elementConafficher(ELEMENT_CONT e)
{
 printf("nom contact : %s \n",e->nom);
 printf("numero contact : %s \n",e->numero);
 printf("email contact : %s \n",e->email);
}

void elementConcopier(ELEMENT_CONT* e1,ELEMENT_CONT e2)
{

}
void elementConaffecter(ELEMENT_CONT* e1,ELEMENT_CONT e2)
{

}
int elementConcomparer(ELEMENT_CONT e1,ELEMENT_CONT e2)
{

}


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

#include "ELTCON.H" 
#include "LSTCON.H"
#include "LISTCONPRIM.H"


NOEUD_CONT noeudConCreer(ELEMENT_CONT e)
{
 NOEUD_CONT n;
 n =(NOEUD_CONT)malloc(sizeof(structNoeudCONT));//Ceci devrait marcher
 if(!n)
  printf ("\nPlus d'espace");
 else
 {
  elementConaffecter(&n->info, e);
  n->suivant = NULL;  
 }
 return n;

}

void noeudConDetruire(NOEUD_CONT n)
{
 elementCondetruire(n->info);
 free(n);
}

LISTE_CONT listeContCreer ( void)
{
 LISTE_CONT l;
 l=(LISTE_CONT)malloc(sizeof(laStructCONT));
 if(!l)
  printf("\nProblème de mémoire");
 else 
 {
  l->lg = 0;
  l->tete = NULL; /* initialiser la tête */
 }
 return(l);
}

void listeContDetruire ( LISTE_CONT l)
{
 int i;
 NOEUD_CONT p, q;
 q= l->tete;
 for(i = 1;i <= l->lg; i++)
 {
  p=q;
  q=q->suivant;
  noeudConDetruire(p);
 }
 free(l);
}

void listeContAfficher (LISTE_CONT l)
{
 int i=1;
 NOEUD_CONT p;
 p= l->tete;
 for(i = 1;i <= l->lg; i++) 
 {
  printf("=== Détails du contact num %d ===\n",i);
  elementConafficher(p->info);
  p= p->suivant;
 }
}

int listeContEstSaturee ( LISTE_CONT l)
{
 int saturee = 1; /* on suppose mémoire saturée */ 
 NOEUD_CONT temp=  (NOEUD_CONT)malloc ( sizeof(structNoeudCONT)); //Pour_CODE_SOURCE Ceci devrait marcher dans tous les cas
 
 if(temp != NULL) 
 {
  saturee = 0; /* mémoire non saturée */
  free(temp);
 }
 return saturee;
}

int listeContEstVide(LISTE_CONT l)
{
 return (l->lg == 0);
}

int insererlisteCont(LISTE_CONT l ,ELEMENT_CONT e,int pos)
{
 int succee=1;
 int i;
 NOEUD_CONT n, p, q; // c des pointeurs sur noeud c equivalent à: // structNoeud * n
 if (listeContEstSaturee(l))
 {
  printf ("\nListe saturée");
  succee=0;
 }
 else 
 {
  if ((pos < 1) || (pos > l->lg + 1)) 
  {
   printf ("\nPosition invalide");
   succee=0;
  }
  else 
  {
   n=noeudConCreer(e); /*on est sûr que la réservation va se faire car la mémoire n'est pas saturée*/
   if (pos == 1) /*insertion en tête de liste*/
   {
    n->suivant=l->tete;
    l->tete = n;
   }
   else /*cas général (pos > 1) */
   {
    q= l->tete;
    for (i=1; i<pos; i++) 
    {
     p = q;
     q = q->suivant;
    }
    // q désigne l'élément de rang pos et p son prédécesseur
    p->suivant=n;
    n->suivant=q;
   }
   (l->lg)++;
  }
 }
 return succee;
}

int supprimerlisteCont(LISTE_CONT l,int pos)
{
 int i;
 int succee=1;
 NOEUD_CONT p, q;
 if (listeContEstVide(l)) 
 {
  printf ("\nListe vide");
  succee=0;
 }
 else
 {
  if ((pos < 1) || (pos > l->lg))
  {
   printf ("\nPosition invalide");
   succee=0;
  }
  else
  {
   q = l->tete;
   /*suppression en tête de liste*/
   if (pos == 1) 
    l->tete=l->tete->suivant;
   else 
   { /*cas général (pos > 1) */
    for (i=1; i<pos; i++)
    {
     p = q;
     q = q->suivant;
    }
    p->suivant=q->suivant;
   }
   // q désigne l'élément de rang pos et p son prédécesseur
   noeudConDetruire(q);
   (l->lg)--;
  }
 }
 return succee;
}

ELEMENT_CONT recupererlisteCont(LISTE_CONT l ,int pos)
{
 /* s'il ya une erreur on affiche un message et on retourne un element vide */
 ELEMENT_CONT elt= elementConcreer();
 int i;
 NOEUD_CONT p;
 if (listeContEstVide(l))
  printf ("\nListe vide");
 else 
 {
  if ((pos < 1) || (pos > l->lg))
  printf ("\nPosition invalide");
  else 
  {
   p= l->tete;
   for (i=1; i<pos; i++)
   p = p->suivant;
   elementConaffecter(&elt,p->info);
  }
 }
 return(elt);
}

LISTE_CONT listeContCopier(LISTE_CONT l)
{
 LISTE_CONT LR = listeContCreer();
 int i;
 ELEMENT_CONT elt;

 for(i = 1;i <= l->lg; i++) 
 {
  elt=elementConcreer();
  elementConcopier(&elt, recupererlisteCont(l,i));
  insererlisteCont(LR,elt, i);
 }
 return LR;
}

int listeContcomparer(LISTE_CONT l1 ,LISTE_CONT l2)
{
 int test= 1;
 int i=1;
 if (listeContTaille(l1) != listeContTaille(l2)) 
  test= 0;
 while ((i<=listeContTaille(l1)) && (test))
 {
  if (!elementConcomparer(recupererlisteCont(l1,i),recupererlisteCont(l2,i)))
   test=0;
  i++;
 }

 return test;
}

int listeContTaille(LISTE_CONT l)
{
 return (l->lg);
}


ELTCON.H
#ifndef _ELTCON_H
#define _ELTCON_H
typedef struct
{
 char nom[50];
 char numero[9];
 char email[30];
}CONTACT,*ELEMENT_CONT;
#endif


ELTCONPRIM.H
#ifndef _ELTCONPRIM_H
#define _ELTCONPRIM_H 
#include "ELTCON.H" 
ELEMENT_CONT elementConcreer(); 
void elementCondetruire(ELEMENT_CONT); 
void elementConafficher(ELEMENT_CONT); 
void elementConcopier(ELEMENT_CONT*,ELEMENT_CONT); 
void elementConaffecter(ELEMENT_CONT*,ELEMENT_CONT); 
int elementConcomparer(ELEMENT_CONT,ELEMENT_CONT); 
#endif


LSTCON.H
#ifndef _LSTCON_H
#define _LSTCON_H
#include "ELTCONPRIM.H"
typedef struct structNoeudCONT
{
 ELEMENT_CONT info;
 struct structNoeudCONT * suivant;
}structNoeudCONT, * NOEUD_CONT;

typedef struct
{
 NOEUD_CONT tete;
 int lg;
}laStructCONT,*LISTE_CONT;

#endif


LISTCONPRIM.H
#ifndef _LSTSMSPRIM_H 
#define _LSTSMSPRIM_H 
#include "LSTCON.H" 

NOEUD_CONT noeudCreer(ELEMENT_CONT e);
LISTE_CONT listeContCreer ( void); 
void listeContDetruire ( LISTE_CONT); 
void listeContAfficher (LISTE_CONT);
int listeContEstSaturee ( LISTE_CONT); 
int listeContEstVide(LISTE_CONT); 
int insererlisteCont(LISTE_CONT,ELEMENT_CONT,int); 
int supprimerlisteCont(LISTE_CONT,int);
ELEMENT_CONT recupererlisteCont(LISTE_CONT,int);
LISTE_CONT listeContCopier(LISTE_CONT); 
int listeContcomparer(LISTE_CONT,LISTE_CONT);
int listeContTaille(LISTE_CONT); 
#endif



--
Commenter la réponse de cs_aymen87
Messages postés
3830
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
19 novembre 2018
0
Merci
As-tu essayé de passer ton code sous GDB ?

Voici ce que ça donne:

gdb$ bt
#0 0x00007ffff7a510d5 in __GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0x00007ffff7a5483b in __GI_abort () at abort.c:91
#2 0x00007ffff7a983dd in __malloc_assert (assertion=<optimized out>, file=<optimized out>, line=<optimized out>, function=<optimized out>) at malloc.c:300
#3 0x00007ffff7a9b944 in sYSMALLOc (av=0x7ffff7dd3720, nb=32) at malloc.c:2448
#4 _int_malloc (av=0x7ffff7dd3720, bytes=16) at malloc.c:3932
#5 0x00007ffff7a9d265 in __GI___libc_malloc (bytes=16) at malloc.c:2924
#6 0x0000000000400a46 in listeContEstSaturee (l=0x404010) at lstcon.c:75
#7 0x0000000000400aa8 in insererlisteCont (l=0x404010, e=0x404030, pos=1) at lstcon.c:95
#8 0x0000000000401188 in ajouterUnContact (listContacts=0x404010) at main.c:142
#9 0x0000000000400f99 in afficherMenuContact (listContacts=0x404010) at main.c:59
#10 0x00000000004010d8 in afficherMenuPrincipal (listContacts=0x404010) at main.c:117
#11 0x0000000000400e91 in main () at main.c:24


Si on va ligne 75 de lstcon.c, on trouve:
 NOEUD_CONT temp=  (NOEUD_CONT)malloc ( sizeof(structNoeudCONT)); //Pour_CODE_SOURCE Ceci devrait marcher dans tous les cas


Ajoutons ceci:
printf("DBG => %i\n", sizeof(structNoeudCONT));
 NOEUD_CONT temp=  (NOEUD_CONT)malloc ( sizeof(structNoeudCONT)); //Pour_CODE_SOURCE Ceci devrait marcher dans tous les cas


On voit a qu'il n'y a effectivement pas de souci. On va donc regarder plus "haut". Plus haut, on voit "insererlisteCont" du fichier lstcon.c:95, suivons-le. Il n'y a rien non, plus, remontons encore. On voir un "ajouterUnContact" du fichier main.c:142.

On voit alors qu'il y a un "elementConcreer", seule différence entre l'appel au début du main, et l'appel fait après.
Donc c'est cette fonction qui provoque des soucis.

En l'analysant, on voit que la structure allouée est trop petite, et donc qu'il y a débordement.
  e = (ELEMENT_CONT)malloc(sizeof(ELEMENT_CONT));


ELEMENT_CONT est un pointeur, donc de taille 4 (ou 8 selon l'archi). Ce qui est bien plus petit que ce qu'il te faut.
J'ai mis ceci:
  e = (ELEMENT_CONT)malloc(sizeof(CONTACT));


Chez moi, ceci solutionne le problème.



Ton vrai problème, c'est que ton code est vraiment sale...
Il y a plein de choses à faire pour le rendre propre:
- On n'écrit pas en tout en majuscule.
- On peut "typedef" une structure, mais jamais un pointeur de structure ! Ca rend les choses illisibles (on ne "cache" pas les pointeurs, c'est une information importante !).
- On malloc en mettant le nom de la variable pour éviter les erreurs de malloc comme tu viens d'avoir.
- Pas besoin de "cast" le retour du malloc si tu utilises un compilateur de C. Le cast n'est nécessaire que si tu utilises un compilateur de C++ (attention, le C++ ne gère pas certaines choses du C, il faut bien utiliser un compilateur de C pour faire du C...).
- Écris tout en anglais plutôt qu'en français (en plus c'est bourré de fautes d'orthographes :p).

Un exemple "PROPRE":
typedef struct
{
  char nom[50];
  char numero[9];
  char email[30];
} Contact;

Contact* createContact() // Ne jamais cacher les pointeurs derrrière un type personnalisé !
{
  Contact* contact = NULL;
  contact = malloc(sizeof(*contact)); // Plus sur de faire comme ceci ! Ansi, si "contact" change de type, la déclaration reste valable.
  memset(contact->email, 0, sizeof(contact->email));
  memset(contact->nom, 0, sizeof(contact->nom));
  memset(contact->numero, 0, sizeof(contact->numero));

  return contact;
}


Applique ceci, partout, et ton code n'en sera que plus fiable.


__________________________________________________________________________________________________

Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
Commenter la réponse de cptpingu
Messages postés
109
Date d'inscription
samedi 3 novembre 2007
Dernière intervention
4 février 2016
0
Merci
Ceci a résolu le problème chez moi aussi.
et merci pour les conseils.
Commenter la réponse de cs_aymen87

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.