IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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 :

[debutant][allocation dynamique] Segmentation fault...


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    x0r
    x0r est déconnecté
    Nouveau membre du Club
    Inscrit en
    Mai 2004
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 5
    Par défaut [debutant][allocation dynamique] Segmentation fault...
    Bonjour, alors voici mon problème et le code qui le crée ;-) :
    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
     
    typedef struct base
    {
    	char* name;
    	char* filename;
    } base;
     
    void SousSaisie(base **data,int n)
    {
    	char buffer[50];
    	int i=0;
     
    	data=(base**)malloc(n*sizeof(base));	
    	//Le debugger m'indique data!=NULL dc pas de pbs d'alloc
    	for(i=0; i < n; i++)
    	{
    		printf("Nom ? ");
    		scanf("%50s",buffer);
    		data[i]->name=(char*)malloc((strlen(buffer)+1)*sizeof(char)); //--> Problème        
            }
    }
    La deuxième allocation en fonctionne pas, pourquoi ?? Sur un tableau de pointeurs sur des structures, j'ai bien le droit d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tab_pointeurs[index]->membre_structure=...
    ?

  2. #2
    Membre éprouvé Avatar de alexrtz
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2003
    Messages
    639
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2003
    Messages : 639
    Par défaut
    Salut,

    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
    void SousSaisie(base **data,int n)
    {
      char buffer[50];
      int i=0;
     
      data = (base**) malloc(n*sizeof(base*));
     
      for(i=0; i < n; i++)
        {
          printf("Nom ? ");
          scanf ("%50s", buffer);
          data[i] = (base*) malloc (sizeof (base));
          data[i] -> name=(char*)malloc((strlen(buffer)+1)*sizeof(char));
        }
    }
    Es-tu sûr de ton coup pour le scanf?
    Je ne sais pas si le 50 prend en comptes le zéro terminal.
    Il vaut mieux utiliser fgets.

  3. #3
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut Re: [debutant][allocation dynamique] Segmentation fault...
    Citation Envoyé par x0r
    Bonjour, alors voici mon problème et le code qui le crée ;-) :
    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
     
    typedef struct base
    {
    	char* name;
    	char* filename;
    } base;
     
    void SousSaisie(base **data,int n)
    {
    	char buffer[50];
    	int i=0;
     
    	data=(base**)malloc(n*sizeof(base));	
    	//Le debugger m'indique data!=NULL dc pas de pbs d'alloc
    	for(i=0; i < n; i++)
    	{
    		printf("Nom ? ");
    		scanf("%50s",buffer);
    		data[i]->name=(char*)malloc((strlen(buffer)+1)*sizeof(char)); //--> Problème        
            }
    }
    Que cherches tu exactement a faire ? Un tableau de n base ou un tableau de n base*.
    Parce que la tu as fait un tableau de n base* (qui eux meme ne sont pas alloue, voir le post de rurouni alex), de plus la valeur de date sera perdu lors du retour a la fonction appelante (passage par valeur).

  4. #4
    Membre très actif
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    258
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 258
    Par défaut
    Citation Envoyé par rurouni alex
    Salut,

    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
    void SousSaisie(base **data,int n)
    {
      char buffer[50];
      int i=0;
     
      data = (base**) malloc(n*sizeof(base*));
     
      for(i=0; i < n; i++)
        {
          printf("Nom ? ");
          scanf ("%50s", buffer);
          data[i] = (base*) malloc (sizeof (base));
          data[i] -> name=(char*)malloc((strlen(buffer)+1)*sizeof(char));
        }
    }
    Es-tu sûr de ton coup pour le scanf?
    Je ne sais pas si le 50 prend en comptes le zéro terminal.
    Il vaut mieux utiliser fgets.
    La solution proposée est correct sauf que :
    1 : En C il n'y a pas de cast sur un pointeur void* ! ( il faut enlever tout les cast des fonctions *alloc)
    2 : les fonctions d'allocations dynamiques peuvent échouer. Pour éviter tout problème il convient de tester la valeur de retour
    3 : scanf() est à proscrire pour faire une saisie utilisateur, pour la simple et bonne raison que cette fonction n'est pas faite pour ca. Il est fortement conseillé d'utiliser la fonction fgets() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    fgets(buffer, sizeof buffer, stdin);
    fgets() inclus le '\n' terminal il faut donc penser à l'enlever ( une brève recherche sur ce forum te donnera le code ce cette fonction, sinon l'écrire est un bon exercice ).
    4 : Ca ne sert à rien d'allouer de la mémoire si on ne copie pas la donnée dedans
    5 : sizeof(char) sera toujours égal à 1 ( d'après la norme C ), il n'est pas utile de le préciser mais ca ne gêne en rien

    Le code devient alors :
    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
     
    void SousSaisie(base **data,int n)
    {
      char buffer[50];
      int i=0;
     
      data = malloc( n * sizeof(base*) );
      if(! data)
      {
            fprintf(stderr, "Erreur d'allocation mémoire\n");
            return;
      }
      for(i=0; i < n; i++)
      {
          printf("Nom ? ");
          fgets(buffer, sizeof(buffer), stdin);
          data[i] =  malloc ( sizeof(base) );
          if(! data[i])
          {
                fprintf(stderr, "Erreur d'allocation mémoire\n");
                return;
          }
          data[i] -> name= malloc( strlen(buffer) + 1);
          if(! data[i] -> name )
          {
                 fprintf(stderr, "Erreur d'allocation mémoire\n");
                 return;
          }
          strcpy(data[i] -> name, buffer);
        }
    }
    Voilà

  5. #5
    Membre émérite
    Profil pro
    Eleveur de cornichons
    Inscrit en
    Juin 2002
    Messages
    1 074
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Eleveur de cornichons
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 074
    Par défaut
    Yabo=Emmanuel ou quoi ?

    Sinon pour le point numéro 5, non ce n'est pas la norme, ça dépend de l'implémentation. Sur les machines 32bits, c'est bien 1, mais il faut que le code soit portable
    Pour les casts, les omettre implique obligatoirement l'inclusion du header <stdlib.h> . On peut utiliser les casts, ce n'est pas interdit par le langage C... C'est une nouvelle façon de coder qu'est de les enlever. Enfin le débat avait été clos lors d'un précédent post
    Bof, voila donc quelques remarques... c'était histoire de poster

    Nas'

  6. #6
    Membre très actif
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    258
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 258
    Par défaut
    Citation Envoyé par gl
    Que cherches tu exactement a faire ? Un tableau de n base ou un tableau de n base*.
    Parce que la tu as fait un tableau de n base* (qui eux meme ne sont pas alloue, voir le post de rurouni alex), de plus la valeur de date sera perdu lors du retour a la fonction appelante (passage par valeur).
    Bien vu ! En effet ton code ne te permettera pas de faire ceci par exemple :

    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
     
    int main(void)
    {
    	base ** p;
    	int i;
    	const int n = 2;
     
    	SousSaisie(p, n);
     
    	i = 0;
    	while(i < n) 
    	{
    		printf("p[%d]->name : %s\n", i, p[i]->name);
    		i++;
    	}
     
     
    	return EXIT_SUCCESS;
    }
    Ce code plante sur le printf (et vu le prototyp de ta fonction je pense que c'est ce que tu veux faire).

    Citation Envoyé par Nasky
    Yabo=Emmanuel ou quoi ?

    Sinon pour le point numéro 5, non ce n'est pas la norme, ça dépend de l'implémentation. Sur les machines 32bits, c'est bien 1, mais il faut que le code soit portable
    [Mode doit être confirmé par Emmanuel] Non c'est défini dans la norme. sizeof(char) == 1 et toutes les autres valeurs sont définies en fonction. Il me semble que qu'Emmanuel avait donné un lien sur Dinkumware concernant le sujet mais pas moyen de retrouver ni le poste ni le passage sur Dinkumware. Manu si jamais tu passes par là [/Mode doit être confirmé par Emmanuel]

    Citation Envoyé par Nasky
    Pour les casts, les omettre implique obligatoirement l'inclusion du header <stdlib.h> . On peut utiliser les casts, ce n'est pas interdit par le langage C... C'est une nouvelle façon de coder qu'est de les enlever. Enfin le débat avait été clos lors d'un précédent post
    Bof, voila donc quelques remarques... c'était histoire de poster

    Nas'
    Non c'est pas interdit, pourquoi faire simple quand on peut faire compliqué

  7. #7
    Membre émérite
    Profil pro
    Eleveur de cornichons
    Inscrit en
    Juin 2002
    Messages
    1 074
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Eleveur de cornichons
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 074
    Par défaut
    Le lien vers la doc proposé par Emmanuel se trouve sur son site, non ?
    J'ai vérifié et sizeof(char) retourne bien 1, quelque soit le système.
    Mais un char ne vaut pas forcément 8 bits (1 octet).
    Explication ici : http://www.isty-info.uvsq.fr/~rumeau/fclc/fclc008.html#q_5

    Nas'

  8. #8
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Nasky
    Sinon pour le point numéro 5, non ce n'est pas la norme, ça dépend de l'implémentation. Sur les machines 32bits, c'est bien 1, mais il faut que le code soit portable
    C'est inexact.

    Je confirme que la définition du langage C précise que sizeof (char) vaut 1 quelque soit l'implémentation. C'est une unité de comptage de la mémoire. Comme toutes les unités elle vaut 1. Rien de mystérieux.

    C'est le nombre de bits qui peut changer selon l'implémentation.

  9. #9
    x0r
    x0r est déconnecté
    Nouveau membre du Club
    Inscrit en
    Mai 2004
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 5
    Par défaut
    Merci pour toutes vos réponses!
    Alors c'est effectivement des sizeof(base*) qu'il faut allouer et pas des sizeof(base)
    Bon alors voici mon code, je vais tout reprendre du début:
    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
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
     
    #define ATTAQUES 1
    #define TECHNIQUES 2
    #define MOUVEMENTS 3
     
    typedef struct base
    {
    	char* name;
    	char* filename;
    } base;
     
    typedef struct all_data
    {
    	base** attaques;
    	base** techniques;
    	base** mouvements;
    	int nbattaques;
    	int nbtechniques;
    	int nbmouvements;
    } all_data;
     
    void Saisie(all_data *data, short choix);
    void SousSaisie(base **data, int n);
     
    int main()
    {
    	all_data data;
    	short choix;
    	printf("1.Attaques\n2.Techniques\n3.Mouvements\n? ");
    	scanf("%hd",&choix);
    	while (choix < 1 || choix > 3)
    	{
    		printf("? ");
    		scanf("%hd",&choix);
    	}
    	Saisie(&data,choix);
            //VideMemoire(...) //Fait les free() sur ce qui a été alloué
     
    void Saisie(all_data *data, short choix)
    {
    	switch(choix) //TODO: Saisie sécurisée
    	{
    		case ATTAQUES:
    			printf("Nombre d'attaques ? ");
    			scanf("%d",&data->nbattaques);
    			SousSaisie(data->attaques,data->nbattaques);
    			break;
    		case TECHNIQUES:
    			printf("Nombre de techniques ? ");
    			scanf("%d",&data->nbtechniques);
    			SousSaisie(data->techniques,data->nbtechniques);
    			break;
    		case MOUVEMENTS:
    			printf("Not Implemented\n");
    			break;
    		default:
    			printf("Program bug...\n");
    	}
    }
     
    void SousSaisie(base **data,int n)
    {
    	char buffer[50];
    	int i=0;
     
    	data=(base**)malloc(n*sizeof(base*));
    	if (data==NULL)
    		fprintf(stderr,"Erreur d'allocation mémoire");		
     
    	for(i=0; i < n; i++)
    	{
    		printf("Nom ? ");
    		fgets(buffer,sizeof(buffer),stdin); // Je m'occuperai du \n plus tard ;-)
    		data[i]->name=(char*)malloc((strlen(buffer)+1)*sizeof(char));
    		if (data[i]->name==NULL)
    			fprintf(stderr,"Erreur d'allocation mémoire");
    		//Je copierai le buffer une fois que l'allocation fonctionnera		
    		//Idem pour data->chemin
    	}
    }
    Ce que je cherche à faire c'est de remplir ma structure all_data !! Du moins dans l'immédiat la partie attaques et techniques.

    Je crois que je dois avoir une erreur avec SousSaisie, il faudrait que je lui passe l'adresse de data->attaques ou data->techniques ?
    Je trouve que ca commence à faire lourd un base ***data ! Il n'y aurait pas une soution plus élégante ?

  10. #10
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par x0r
    Ce que je cherche à faire c'est de remplir ma structure all_data !! Du moins dans l'immédiat la partie attaques et techniques.
    Il y a deux façon de modifier la valeur d'un objet avec une fonction :

    Si l'objet est un pointeur, la regle est la même :

  11. #11
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Yabo
    1 : En C il n'y a pas de cast sur un pointeur void* ! ( il faut enlever tout les cast des fonctions *alloc)
    [mode pinaillage sur les termes]
    Non, il peut y avoir des cast sur un pointeur void* en C, ce n'est pas obligatoire c'est tout.
    Et non il ne faut pas enlever les cast des fonctions *alloc, mais on peut enlever les cast.
    Le code avec ou sans cast est aussi valide (a condition bien sur de tester le retour, d'inclure les entete necessaires, etc..), apres certains estiment qu'il est preferable de ne pas les mettre, d'autre que si et chacun a des arguments valables.
    [/mode pinaillage]

  12. #12
    Membre très actif
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    258
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 258
    Par défaut
    Citation Envoyé par gl
    [mode pinaillage sur les termes]
    Non, il peut y avoir des cast sur un pointeur void* en C, ce n'est pas obligatoire c'est tout.
    Et non il ne faut pas enlever les cast des fonctions *alloc, mais on peut enlever les cast.
    Le code avec ou sans cast est aussi valide (a condition bien sur de tester le retour, d'inclure les entete necessaires, etc..), apres certains estiment qu'il est preferable de ne pas les mettre, d'autre que si et chacun a des arguments valables.
    [/mode pinaillage]
    Je suis tout a fait d'accord j'ai pris le mauvais ton dans mon poste ( j'essaie de faire attention pourtant ). Donc je reformule

    1 : Le C standard permet de ne pas mettre de cast sur les pointeurs void*. Le cast sur les fonctions *alloc n'est donc pas obligatoire.


  13. #13
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Yabo
    1 : Le C standard permet de ne pas mettre de cast sur les pointeurs void*. Le cast sur les fonctions *alloc n'est donc pas obligatoire.
    Voilà!

  14. #14
    x0r
    x0r est déconnecté
    Nouveau membre du Club
    Inscrit en
    Mai 2004
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 5
    Par défaut
    C'est bon mon problème est résolu !
    L'erreur était toute bête en plus:
    J'ai fait un malloc pour mes base** et pour les base* mais je n'avais pas fait de malloc pour mes base !! Il me manquait un data[i]=malloc(sizeof(base))

    Merci pour votre aide

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Debutant , gestion d'une file , segmentation fault
    Par Freedom57 dans le forum Débuter
    Réponses: 4
    Dernier message: 22/12/2010, 16h52
  2. Segmentation fault (debutant)
    Par maserati dans le forum C
    Réponses: 6
    Dernier message: 26/11/2008, 14h29
  3. [debutant] allocation dynamique d'un tableau.
    Par méphistopheles dans le forum Débuter
    Réponses: 3
    Dernier message: 16/03/2007, 12h45
  4. Réponses: 6
    Dernier message: 04/01/2007, 01h30
  5. [debutant] : Allocation de mémoire dynamique
    Par sam.fet dans le forum Langage
    Réponses: 5
    Dernier message: 15/02/2006, 14h58

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