segment fault pour du C (tabl d'élément)

segment fault pour du C (tabl d'élément) - C - Programmation

Marsh Posté le 26-09-2005 à 12:00:35    

Boujour tout le monde, un bail, n'est-ce pas ? hm passons.
 :pfff:  
En fait je dois écrire un annuaire en c, qui doit pouvoir gérer l'insertion de nouveaux...élèves, mettons, la suppression, la recherche...
 
Oui sauf que je me retrouve avec une insertion gérée sans défaut, mais qui n'a pas lieu concretement.
Avec à la fin de l'execution un segment fault... :non:  
Si vous avez un petit tuyau ça serait nickel pour l'UC, sinon j'ai pas fini de la faire chauffer XD
 
 
Mici ^___^' :D  
 

Code :
  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. # include <malloc.h>
  4. /**************************************************************
  5. *
  6. *
  7. * Le programme annuaire1.c :
  8. * - crée un tableau comportant les noms et numéros d'étudiant
  9. * - demande à l'utilisateur un nom et une commande  
  10. *  - i(insere), c(cherche), s(supprime), q(quitte)
  11. *
  12. * - effectue les actions appropriées
  13. *
  14. ***************************************************************/
  15. struct ID{
  16. char* nom;
  17. int no;
  18. }tab[10];
  19. // Affichage du tableau
  20. void Show()
  21. { int i;
  22. for(i=0; i<10;i++)
  23. {tab[i].no=3+i; printf("étudiant [%d] : %s %d\n",i, tab[i].nom, tab[i].no );}
  24. }
  25. // Traitements
  26. void Insert(char* ftmp)
  27. {
  28. int j; int nm; int o;
  29. for(j=0;j<10;j++)
  30. {
  31.  if(tab[j].nom==NULL){
  32.   tab[j].nom=ftmp;
  33.   printf("Quel est son numéro d'étudiant ? \n" );
  34.   scanf("%d",&nm);
  35.   tab[j].no=nm;
  36. // printf("étudiant [%d] : %s %d \n", j,tab[j].nom, tab[j].no);
  37.   break; }
  38. }
  39. /*   printf("Ou voulez vous l'inserer ? \n" );
  40.   scanf("%d",&o);
  41.   tab[o].nom=ftmp;
  42.   printf("Quel est son numéro d'étudiant ? \n" );
  43.   scanf("%d",&nm);
  44.   tab[o].no=nm;  
  45. */
  46. printf("Insertion succeeded\n" );
  47. Show();
  48. }
  49. void Search(char* ftmp){printf("Searching...\n" ); }
  50. void Supp(char* ftmp){printf("Removing...\n" ); }
  51. // Détermine le traitement à faire en fonction de la commande entrée
  52. void Proc()
  53. {
  54. char *ftmp;
  55. char com;
  56. ftmp=(char*)calloc(10,sizeof(char));
  57. printf("Entrez un nom : \n" );
  58. scanf("%s",&ftmp);
  59. printf("Entrez une commande : \n" );
  60. scanf("%s",&com);
  61. switch (com){
  62. case ('i'):
  63. Insert(ftmp); break;
  64. case ('c'):
  65. Search(ftmp); break;
  66. case ('r'):
  67. Supp(ftmp); break;
  68. case('q') : printf("Exit !\n" ); exit;
  69.  }
  70. }
  71. // Initialise le tableau comportant noms et numéros d'élève
  72. void Ini()
  73. {
  74. int i;
  75. tab[0].nom="Noi";   tab[1].nom="Daisuki";
  76. tab[2].nom="Kaioshin"; tab[3].nom="Ori";
  77. }
  78. int main(int argc , char *argv[])
  79. {
  80. Ini();
  81. Proc();
  82. // Show();
  83. return 0;
  84. }


Message édité par kinokoShan le 26-09-2005 à 12:02:00
Reply

Marsh Posté le 26-09-2005 à 12:00:35   

Reply

Marsh Posté le 26-09-2005 à 12:07:41    

Variable globale, ça commence mal...  
 
Retour de calloc() non testé, c'est mauvais.
 
Tu ne maîtrises visiblement pas scanf(), il vaut mieux s'en tenir à des fonctions type fgets() pour ce genre de chose... scanf() n'est pas trivial, de la manière dont tu l'utilises c'est très facile de faire planter ton programme.
 
Ensuite plutôt que de mettre des "10" partout, déclare un #define MAXLENGTH par exemple qui va te servir et pour la limite de ton tableau, et pour la limite de tes for().
Le jour où tu voudras mettre 100, tu n'auras qu'une seule ligne à changer (enfin ce serait mieux avec du dynamique, genre un malloc() de 10 puis des realloc() si besoin).
 
Je vois que tu testes des tab[...].nom == NULL, mais ton tableau n'est jamais initialisé. Tes structures contiennent potentiellement n'importe quoi.
 
Pas le courage de regarder le reste pour le moment, ce serait cool que tu fasses le ménage dans ton code (et dans ton indentation), et que tu tentes d'isoler le problème.
Avec un debugger, par exemple.


Message édité par Elmoricq le 26-09-2005 à 12:12:26
Reply

Marsh Posté le 26-09-2005 à 12:14:01    

tu fais un switch sur un char * et tes cases portent sur un char, y'a merde la

Reply

Marsh Posté le 26-09-2005 à 12:15:16    

chrisbk a écrit :

tu fais un switch sur un char * et tes cases portent sur un char, y'a merde la


 
Ah oui bien vu, j'ai le sentiment que le scanf() devrait contenir %c pour com. Enfin fgetc() serait de toute manière plus sage.

Reply

Marsh Posté le 27-09-2005 à 10:38:42    

je switch sur un char. com est défini en char, c'est la commande qui est tapée par l'user. -pour le reste, je corrige, mici ^____^

Reply

Marsh Posté le 27-09-2005 à 10:46:39    

kinokoShan a écrit :

je switch sur un char. com est défini en char, c'est la commande qui est tapée par l'user. -pour le reste, je corrige, mici ^____^


oui, mais bon ... vu la manière dont tu l'utilises dans ton scanf, y'a un petit souci quelque part, hein :o
 
et d'ailleurs, pourquoi tu passes une fois un char ** à ton scanf et une autre fois un char * pour le même formatage (%s) ? Vérifie ce que tu attends (et scanf, c'est pas terrible, pour écrire du code fiable :/ )

Reply

Marsh Posté le 27-09-2005 à 11:13:17    

Pour scanf, je veux bien te croire, mais j'ai testé avec scanf("%c",com) et il ne prend pas la commande, il finit tout de suite... -atta j'essaie avec fgets ! X+

Reply

Marsh Posté le 27-09-2005 à 11:24:57    

kinokoShan a écrit :

Pour scanf, je veux bien te croire, mais j'ai testé avec scanf("%c",com) et il ne prend pas la commande, il finit tout de suite... -atta j'essaie avec fgets ! X+


 
 [:le poney de mr pink]  
 
scanf("%c", &com)
 
Je crois que tu devrais faire une pause dans ton programme, et que tu étudies les pointeurs le temps de quelques exercices simples, pour que tu puisses y voir plus clair. Parce que j'ai le sentiment que tu t'emmêles les pinceaux, ça va te porter préjudice par la suite.
Evite le jeu du "je teste jusqu'à ce que ça fonctionne", c'est le meilleur moyen de créer du bancal et de l'instable.
 
 
Et si tu veux utiliser autre chose que scanf() (ce que je te recommande), pour la saisie d'un seul caractère, utilise fgetc() plutôt que fgets().
 

Reply

Marsh Posté le 27-09-2005 à 12:42:01    

:(  c'est po ma faute
*révise révise*  
 
Bon maintenant c'est un segment fault sur le case ('s') au niveau du

Code :
  1. if(*(tab[j].nom)==*ftmp)


...
Le code en intégralité ...?

Code :
  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. # include <malloc.h>
  4. /**************************************************************
  5. * Auteurs : Corcelle, Corselle, Zhang
  6. * Exercice :
  7. * Date : 21/09/2005
  8. * Description de l'exercice :  
  9. * - allocation d'espace mémoire
  10. * - libération d'espace mémoire
  11. * - manipulation et affichage  
  12. *
  13. * Le programme annuaire1.c :
  14. * - crée un tableau comportant les noms et numéros d'étudiant
  15. * - demande à l'utilisateur un nom et une commande  
  16. *  - i(insere), c(cherche), s(supprime), q(quitte)
  17. *
  18. * - effectue les actions appropriées
  19. *
  20. ***************************************************************/
  21. #define MAXLENGTH 10
  22. typedef struct {
  23. char* nom;
  24. int no;
  25. }ID;
  26. int main(int argc , char *argv[])
  27. {
  28. int i,j,nm;
  29. char com;
  30. char *ftmp=(char*)malloc(MAXLENGTH*sizeof(char)+1);
  31. // Allocation mémoire pour ID* tab
  32. ID* tab=(ID*)malloc(MAXLENGTH*sizeof(ID));
  33. if (tab==NULL)
  34. {
  35.  printf("malloc failed\n" );
  36.  exit(1);
  37. }
  38. // Initialisation de tab
  39. tab[0].nom="Alexys"; tab[0].no=1235;
  40. tab[1].nom="Koebi";  tab[1].no=3345;
  41. tab[2].nom="Nido";  tab[2].no=8775;
  42. tab[3].nom="Fred";  tab[3].no=7422;
  43. tab[4].nom="Corinne"; tab[4].no=74520;
  44. //Proc();
  45. printf("Entrez un nom : \n" );
  46. gets(ftmp);
  47. printf("Entrez une commande : \n(i,s,r,q ?)\n" );
  48. com=getchar();
  49.  switch (com)
  50.  {
  51.   case ('i'):
  52.    // Queued  
  53.    for(j=0;j<MAXLENGTH;j++)
  54.    {
  55.     // Inserting
  56.     if(tab[j].nom==NULL)
  57.     {
  58.                         tab[j].nom=ftmp;
  59.      printf("Quel est son numéro détudiant ? \n" );
  60.      scanf("%d",&nm);
  61.      tab[j].no=nm;
  62.      break;
  63.     }
  64.    }
  65.   break;
  66.   case ('s'):
  67.    // SEGMENT FAULT after displaying
  68.    printf("find : %s\n",ftmp);
  69.    for(j=0;j<MAXLENGTH;j++)
  70.    {
  71.     // Searching
  72.     if(*(tab[j].nom)==*ftmp)
  73.      printf("Etudiant numéro %d : %s \n",tab[j].no, tab[j].nom);
  74.    }
  75.   break;
  76.   case ('r'):
  77.    // Removing  
  78.   break;
  79.   case('q') : printf("Exit !\n" ); exit;
  80.  }
  81. for(i=0;i<MAXLENGTH;i++)
  82.  printf("étudiant no %d : %s\n",tab[i].no,tab[i].nom);
  83. free (ftmp);
  84. free (tab);
  85. return 0;
  86. }

:sweat:

Reply

Marsh Posté le 27-09-2005 à 12:42:21    

:(  c'est po ma faute
*révise révise*  
 
Bon maintenant c'est un segment fault sur le case ('s') au niveau du

Code :
  1. if(*(tab[j].nom)==*ftmp)


...
Le code en intégralité ...?

Code :
  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. # include <malloc.h>
  4. /**************************************************************
  5. *
  6. *
  7. * Le programme annuaire1.c :
  8. * - crée un tableau comportant les noms et numéros d'étudiant
  9. * - demande à l'utilisateur un nom et une commande  
  10. *  - i(insere), c(cherche), s(supprime), q(quitte)
  11. *
  12. * - effectue les actions appropriées
  13. *
  14. ***************************************************************/
  15. #define MAXLENGTH 10
  16. typedef struct {
  17. char* nom;
  18. int no;
  19. }ID;
  20. int main(int argc , char *argv[])
  21. {
  22. int i,j,nm;
  23. char com;
  24. char *ftmp=(char*)malloc(MAXLENGTH*sizeof(char)+1);
  25. // Allocation mémoire pour ID* tab
  26. ID* tab=(ID*)malloc(MAXLENGTH*sizeof(ID));
  27. if (tab==NULL)
  28. {
  29.  printf("malloc failed\n" );
  30.  exit(1);
  31. }
  32. // Initialisation de tab
  33. tab[0].nom="Alexys"; tab[0].no=1235;
  34. tab[1].nom="Koebi";  tab[1].no=3345;
  35. tab[2].nom="Nido";  tab[2].no=8775;
  36. tab[3].nom="Fred";  tab[3].no=7422;
  37. tab[4].nom="Corinne"; tab[4].no=74520;
  38. //Proc();
  39. printf("Entrez un nom : \n" );
  40. gets(ftmp);
  41. printf("Entrez une commande : \n(i,s,r,q ?)\n" );
  42. com=getchar();
  43.  switch (com)
  44.  {
  45.   case ('i'):
  46.    // Queued  
  47.    for(j=0;j<MAXLENGTH;j++)
  48.    {
  49.     // Inserting
  50.     if(tab[j].nom==NULL)
  51.     {
  52.                         tab[j].nom=ftmp;
  53.      printf("Quel est son numéro détudiant ? \n" );
  54.      scanf("%d",&nm);
  55.      tab[j].no=nm;
  56.      break;
  57.     }
  58.    }
  59.   break;
  60.   case ('s'):
  61.    // SEGMENT FAULT after displaying
  62.    printf("find : %s\n",ftmp);
  63.    for(j=0;j<MAXLENGTH;j++)
  64.    {
  65.     // Searching
  66.     if(*(tab[j].nom)==*ftmp)
  67.      printf("Etudiant numéro %d : %s \n",tab[j].no, tab[j].nom);
  68.    }
  69.   break;
  70.   case ('r'):
  71.    // Removing  
  72.   break;
  73.   case('q') : printf("Exit !\n" ); exit;
  74.  }
  75. for(i=0;i<MAXLENGTH;i++)
  76.  printf("étudiant no %d : %s\n",tab[i].no,tab[i].nom);
  77. free (ftmp);
  78. free (tab);
  79. return 0;
  80. }

:sweat:

Reply

Marsh Posté le 27-09-2005 à 12:42:21   

Reply

Marsh Posté le 27-09-2005 à 12:43:19    

euh oups (fausse manoeuvre)

Reply

Marsh Posté le 27-09-2005 à 13:09:09    

Je me permets d'ajouter des commentaires à ton code, ce sera plus simple je pense :
 

Code :
  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. # include <malloc.h>
  4. #define MAXLENGTH 10
  5. typedef struct {
  6.     char* nom;
  7.     int no;
  8. }ID;
  9.    
  10. int main(int argc , char *argv[])
  11. {
  12.     int i,j,nm;
  13.     char com;
  14.     /* 1. le cast sur un void* est inutile
  15.        2. la multiplication est prioritaire sur l'addition, ta ligne ne  
  16.           fonctionne que parce que sizeof(char) == 1  
  17.           Tu aurais dû écrire : (MAXLENGTH+1) * sizeof(char)  
  18.        3. Tu *DOIS* tester le retour de ton allocation memoire.  
  19.           Si malloc() echoue, tu auras droit a de mechantes surprises.
  20.        char *ftmp = malloc((MAXLENGTH + 1) * sizeof *ftmp);     
  21.        if ( ftmp == NULL ) {
  22.            ...
  23.        }
  24.     */
  25.     char *ftmp=(char*)malloc(MAXLENGTH*sizeof(char)+1);
  26.     /* Idem ici, cast inutile :  
  27.        ID *tab = malloc( MAXLENGTH * sizeof *tab) */
  28.     ID* tab=(ID*)malloc(MAXLENGTH*sizeof(ID));   
  29.    
  30.     if (tab==NULL)
  31.     {
  32.         /* Par convention, on imprime sur le flux d'erreur :
  33.            fprintf(stderr, "malloc failed\\n" ); */
  34.         printf("malloc failed\\n" );
  35.         exit(1);
  36.     }
  37.    
  38.     // Initialisation de tab
  39.     tab[0].nom="Alexys";    tab[0].no=1235;   
  40.     tab[1].nom="Koebi";     tab[1].no=3345;   
  41.     tab[2].nom="Nido";      tab[2].no=8775;   
  42.     tab[3].nom="Fred";      tab[3].no=7422;
  43.     tab[4].nom="Corinne";   tab[4].no=74520;
  44.    
  45.    
  46.     printf("Entrez un nom : \\n" );
  47.     /* SURTOUT PAS ! gets() NE DOIT PAS ETRE UTILISE !
  48.        Cette fonction est un bug, elle n'est encore la  
  49.        que par souci de compatibilite.
  50.        Ne jamais, jamais, jamais l'utiliser. Jamais.  
  51.        Utiliser fgets() : fgets(ftmp, MAXLENGTH, stdin); */
  52.     gets(ftmp);
  53.     printf("Entrez une commande : \n(i,s,r,q ?)\n" );
  54.     com=getchar();
  55.    
  56.     /* tu ne passes qu'une seule fois par ton switch(), je pense qu'il te
  57.        manque une boucle ou quelque chose... */
  58.     switch (com)
  59.     {
  60.         case ('i'):
  61.             // Queued  
  62.             for(j=0;j<MAXLENGTH;j++)
  63.             {
  64.                 /* Non, pour la raison suivante : quand tu utilises  
  65.                    malloc(), la memoire allouee contient n'importe quoi.
  66.                    Soit tu utilises calloc() et tu peux effectuer ce  
  67.                    test, soit apres ton malloc() tu utilises memset() a  
  68.                    la suite de ton malloc().
  69.                    Mais en l'etat actuel, tab[j] pourrait ne jamais  
  70.                    retourner NULL, meme si la moitie de ton tableau  
  71.                    n'est pas initialise.
  72.                 */
  73.                 if(tab[j].nom==NULL)
  74.                 {
  75.                     /* Hmm. Es-tu sur de vouloir faire ca ? Ici tu  
  76.                        donnes l'adresse de ftmp a tab[j].nom. Ce qui fait
  77.                        que si ftmp change, tab[j].nom change aussi,  
  78.                        puisque les deux  pointent sur le meme bout de  
  79.                        memoire.
  80.                        Il vaut mieux faire un strdup(), par exemple. */
  81.                     tab[j].nom=ftmp;       
  82.                     printf("Quel est son numéro détudiant ? \\n" );   
  83.                    
  84.                     /* evite scanf() si possible... ici, utilise plutot
  85.                        fgets() + strtol() pour convertir la chaine lue
  86.                        en un entier */
  87.                     scanf("%d",&nm);
  88.                     tab[j].no=nm;
  89.                     break;
  90.                 }
  91.             }
  92.         break;
  93.         case ('s'):
  94.             printf("find : %s\\n",ftmp);
  95.            
  96.             for(j=0;j<MAXLENGTH;j++)
  97.             {
  98.                 /* tout d'abord, utiliser
  99.                    strcmp() pour comparer deux chaines de caracteres.  
  100.                    Parce que la, tu ne fais que comparer deux pointeurs,
  101.                    ce qui est tout a fait different. En plus tu les  
  102.                    compares mal, puisque tu compares les adresses des  
  103.                    variables tab[j].nom et ftmp, et non leur contenu.  
  104.                    Normalement, ton if n'est jamais vrai.
  105.                    Du coup, il est pas ici ton segfault */
  106.                 if(*(tab[j].nom)==*ftmp)
  107.                     printf("Etudiant numéro %d : %s \\n",tab[j].no, tab[j].nom);   
  108.             }           
  109.         break;
  110.         case ('r'):
  111.    
  112.         break;
  113.         case('q') : printf("Exit !\\n" ); exit;
  114.     }
  115.    
  116.    
  117.    
  118.    
  119.     /* Ah ouais mais non, il est *ICI* ton segfault :
  120.        de i a MAXLENGTH, il n'y a que les 5 premieres cases  
  121.        d'initialisees.
  122.        Le probleme c'est que tu lui demandes d'afficher des cases  
  123.        de tab[] qui pointent sur n'importe quoi en memoire. C'est un  
  124.        probleme parce que du coup il va lire ce qui est pointe par
  125.        tes variables, et il y a de bonnes chances pour que soit l'adresse
  126.        ne veuille rien dire, soit elle pointe sur un truc qui n'appartient
  127.        pas a ton programme. Donc plantage.
  128.        
  129.        Ca c'est le cas 1. Parce que j'ai le sentiment que ton  
  130.        compilateur, qui est trop gentil, t'initialises tes variables a
  131.        NULL par defaut. Ne compte jamais sur ce comportement, la norme  
  132.        veut que ce soit indefini. Mais, bref, dans tous les cas tu fais  
  133.        un printf() de NULL, et ca, ca mene aussi au segfault  
  134.  
  135.        Bref, ne jamais utiliser de variables non initialisees */
  136.     for(i=0;i<MAXLENGTH;i++)
  137.         printf("étudiant no %d : %s\n",tab[i].no,tab[i].nom);
  138.    
  139.     free (ftmp);   
  140.     free (tab);
  141.     return 0;
  142. }


 
EDIT : foutu forum et son interprétation des backslash :fou:


Message édité par Elmoricq le 27-09-2005 à 13:28:19
Reply

Marsh Posté le 27-09-2005 à 14:06:54    

Mici c'est très complet ! Je corrige et je ferais un rapport détaillé XD
-vu la tonne d'erreur, chuis en train de me dire que je vire Microsoftienne oÔ-
 
^____^

Reply

Marsh Posté le 27-09-2005 à 15:08:16    

kinokoShan a écrit :

Mici c'est très complet ! Je corrige et je ferais un rapport détaillé XD


 
J'ai pas examiné ce code en détail (j'espère que Taz ne tombera jamais dessus un jour parce que tu vas comprendre ta douleur)... mais il me semble que, pour rajouter un nom, tu utilises l'algo suivant:
1) faire saisir le nom dans la variable "ftmp"
2) stocker l'adresse de cette variable dans "tab[i].nom"
 
Si vraiment c'est ça, alors en final tu auras un tableau de "n" éléments contenant tous la même adresse, à savoir l'adresse de "ftmp". Donc, si tu affiches ton annuaire tu auras à l'écran "n" fois le dernier nom saisi...
 
De plus, ce genre d'instruction "if (*tab[i].nom == *ftmp)" c'est absolument pas bon. Tu ne fais que comparer le premier octet de "tab[i].nom" avec le premier octet de "ftmp". Et n'enlève surtout pas l'étoile, car cela reviendrait à comparer des adresses !!!
 
Suis les conseils de Elmoricq. Fais une pause, étudie en détail comment fonctionne un pointeur et une chaîne de caractères puis recommence tranquillement. T'as un bon cours de C ici http://fr.lang.free.fr/cours/Langa [...] e_v2.0.pdf qui explique bien les pointeurs au chapitre X (page 58)
 
En général, pour ce genre d'algo (insertion/suppression), on utilise de préférence une liste chaînée. Chaque élément contient ses infos plus l'adresse de l'élément suivant. Cela permet d'insérer ou de supprimer très facilement un des éléments intermédiaires sans avoir besoin de tout décaler ce qu'il y a après...
 

kinokoShan a écrit :

-vu la tonne d'erreur, chuis en train de me dire que je vire Microsoftienne oÔ-


C'est pas faux...

Message cité 1 fois
Message édité par Sve@r le 27-09-2005 à 15:09:58
Reply

Marsh Posté le 27-09-2005 à 15:11:16    

Sve@r a écrit :

En général, pour ce genre d'algo (insertion/suppression), on utilise de préférence une liste chaînée. Chaque élément contient ses infos plus l'adresse de l'élément suivant. Cela permet d'insérer ou de supprimer très facilement un des éléments intermédiaires sans avoir besoin de tout décaler ce qu'il y a après...


 
+1
Je ne l'ai pas mentionné parce que je me suis dit que c'était déjà assez difficile comme ça avec un simple tableau. ;)
 
Pas de secret, faut bosser les pointeurs, là ça part trop dans tous les sens.

Reply

Marsh Posté le 30-09-2005 à 11:46:18    

Okish je m'y mets *retrousse ses manches*  
Mici les gars ^______^

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed