Ou est l'erreur de segmentation ?

Ou est l'erreur de segmentation ? - C - Programmation

Marsh Posté le 07-08-2006 à 14:02:37    

Bonjour,
 
cet exo est tiré d'un examen qui a été donné dans la fac ou je suis.
Les erreurs sont censées être trouvées en lisant le code mais comme je ne trouvais rien d'anormal, j'ai compilé et exécuté le programme.
Aucune erreur de segmentation n'a été décelée.
Je voudrais donc savoir si quelqu'un voyait quelques choses d'anormal dans ce code car il doit vraiment y avoir une ou plusieurs erreurs car l'exo a été donné en examen  :)  
 

Citation :

L'execution du programme suivant produit une erreur de segmentation. Expliquez pourquoi.
L'execution

Code :
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4. void bubbleSort(char **tab, int (*cmp)(void *, void *))
  5. {
  6.   char **p1, **p2;
  7.   for(p1=tab; *p1!=NULL; ++p1)
  8.     for(p2=p1+1; *p2!=NULL; ++p2)
  9.       if((*cmp)(p1,p2)>0)
  10. {
  11.   char *tmp;
  12.   tmp = *p1;
  13.   *p1 = *p2;
  14.   *p2 = tmp;
  15. }
  16. }
  17. void printTable(FILE *fdo, char **tab)
  18. {
  19.   for(; *tab!=NULL; ++tab) fprintf(fdo,"%s\n", *tab);
  20. }
  21. int main(int argc, char *argv[])
  22. {
  23.   char **t; unsigned int i,l;
  24.   if((t=(char**)malloc(sizeof(char*)*argc))==NULL)
  25.     {
  26.       fprintf(stderr,"Error in memory allocation\n" );
  27.       return EXIT_FAILURE;
  28.     }
  29.   l=(unsigned int)argc-1U;
  30.   for(i=0U; i<l; ++i)
  31.     {
  32.       if((t[i]=(char*)malloc(strlen(argv[i+1])+1))==NULL)
  33. {
  34.   fprintf(stderr,"Error in memory allocation\n" );
  35.   return EXIT_FAILURE;
  36. }
  37.       strcpy(t[i],argv[i+1]);
  38.     }
  39.   t[l]=NULL;
  40.   printTable(stdout,t);
  41.   bubbleSort(t, (int (*)(void *, void *))&strcmp);
  42.   printf("\n" );
  43.   printTable(stdout, t);
  44.   return EXIT_SUCCESS;
  45. }



Message édité par Gattuso le 07-08-2006 à 14:04:49
Reply

Marsh Posté le 07-08-2006 à 14:02:37   

Reply

Marsh Posté le 07-08-2006 à 14:31:05    

Effectivement, à l'arrache, je ne vois pas trop le souci.
Il faut en tout cas bien examiner les affectations de pointeurs (strcpy, =) en fonction de la taille allouée pour chacun d'entre eux.
Je m'y repencherais si j'ai un peu de tps aujourd'hui

Reply

Marsh Posté le 07-08-2006 à 14:36:36    

Je ne sais pas si c'est ce que ton prof attendait, mais il y a au moins une erreur dans la fonction bubbleSort, ligne 10.
Si je ne me trompe pas, il faut mettre  (*cmp)(*p1,*p2)  au lieu de (*cmp)(p1,p2).
 Dans tous les cas où j'ai testé, je n'ai pas eu de segfault, mais ce genre de choses pourrait bien en causer une. En tous cas, il est clair que le programme en l'état ne fait pas ce qu'on veut (à savoir trier la liste de ses arguments).


---------------
TriScale innov
Reply

Marsh Posté le 07-08-2006 à 16:21:29    

franceso a écrit :

En tous cas, il est clair que le programme en l'état ne fait pas ce qu'on veut (à savoir trier la liste de ses arguments).


Hum... l'algo du bubblesort veut qu'on recommence le balayage tant qu'on a eu au-moins une permutation. Là, je ne vois pas de flag indiquant qu'il faut recommencer...

Message cité 1 fois
Message édité par Sve@r le 07-08-2006 à 16:41:56

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 07-08-2006 à 16:24:34    

euh, p1 et p2 sont des char**... je pense que franceso a raison.

Reply

Marsh Posté le 07-08-2006 à 16:29:18    

Elmoricq a écrit :

euh, p1 et p2 sont des char**... je pense que franceso a raison.


Exact. J'ai mal regardé - Je rectifie mon post précédent...
En revanche, je ne vois pas trop l'erreur...


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 07-08-2006 à 16:30:33    

Sve@r a écrit :

Exact. J'ai mal regardé - Je rectifie mon post précédent...
En revanche, je ne vois pas trop l'erreur...


 
ben comme le dit franceso, en passant des char** à strcmp(), on n'obtient pas le comportement attendu.

Reply

Marsh Posté le 07-08-2006 à 16:34:25    

Elmoricq a écrit :

ben comme le dit franceso, en passant des char** à strcmp(), on n'obtient pas le comportement attendu.


Non, je comprends bien que si strcmp ne reçoit pas la bonne adresse il va pointer n'importe où. Ce que je ne voyais pas, c'est pourquoi l'algo même débugé par Francesco ne fonctionnait pas. Puis j'ai vu qu'il manquait le flag de répétition de balayage...


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 07-08-2006 à 16:34:46    

Sve@r a écrit :

Hum... l'algo du bubblesort veut qu'on recommence le balayage tant qu'on a eu au-moins une permutation. Là, je ne vois pas de flag indiquant qu'il faut recommencer...


dans le bubble sort, on fait N passages (ou N est la taille du tableau).
 
edit : http://en.wikipedia.org/wiki/Bubble_sort


Message édité par jagstang le 07-08-2006 à 16:37:41

---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 07-08-2006 à 16:40:57    

Sve@r a écrit :

Non, je comprends bien que si strcmp ne reçoit pas la bonne adresse il va pointer n'importe où. Ce que je ne voyais pas, c'est pourquoi l'algo même débugé par Francesco ne fonctionnait pas. Puis j'ai vu qu'il manquait le flag de répétition de balayage...


Le flag de répétition du balayage n'est qu'une amélioration du bubblesort. Dans l'algo implémenté ici, on fait toujours N passages (ce qui est n'est en général pas nécessaire, mais suffit toujours pour trier tout le tableau).


---------------
TriScale innov
Reply

Marsh Posté le 07-08-2006 à 16:40:57   

Reply

Marsh Posté le 07-08-2006 à 16:43:46    

franceso a écrit :

Le flag de répétition du balayage n'est qu'une amélioration du bubblesort. Dans l'algo implémenté ici, on fait toujours N passages (ce qui est n'est en général pas nécessaire, mais suffit toujours pour trier tout le tableau).


Exact. Bon, je suis pas au top today... vaut mieux que j'arrête de m'enfoncer tout seul... :sol:
 
Edit: Pourquoi en ligne 44 du pgm initial le "étoile" est entre parenthèses tout seul ?

Citation :

Code :
  1. bubbleSort(t, (int (*)(void *, void *))&strcmp);



Moi je verrais mieux

Code :
  1. bubbleSort(t, int (*(void *, void *))&strcmp);


Mais je comprends rien à cette syntaxe alambiquée. Intuitivement, j'aurais simplement écrit

Code :
  1. bubbleSort(t, strcmp);


Message cité 2 fois
Message édité par Sve@r le 07-08-2006 à 16:54:40

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 07-08-2006 à 16:47:24    

Sve@r a écrit :

Exact. Bon, je suis pas au top today... vaut mieux que j'arrête de m'enfoncer tout seul... :sol:


[:lorill]


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 07-08-2006 à 17:07:15    

Sve@r a écrit :

Edit: Pourquoi en ligne 44 du pgm initial le "étoile" est entre parenthèses tout seul ?

Je pense que c'est la seule syntaxe valide pour exprimer le cast vers un type fonction.
 

Sve@r a écrit :

Mais je comprends rien à cette syntaxe alambiquée. Intuitivement, j'aurais simplement écrit

Code :
  1. bubbleSort(t, strcmp);



C'est ce que j'aurais fait aussi intuitivement, mais je viens d'essayer et ça ne marche pas : le compilateur renvoit systématiquement un warning. C'est étrange : je ne vois pourtant pas ce qui est différent entre ce programme et quelque chose dans le genre de l'appel système "signal", pour lequel je n'ai jamais eu besoin de caster explicitement mes adresses de fonctions...


---------------
TriScale innov
Reply

Marsh Posté le 07-08-2006 à 17:11:09    

En remplaçant :

Code :
  1. if((*cmp)(p1,p2)>0)


par  

Code :
  1. if((*cmp)(*p1,*p2)>0)


On obtient le tri des mots que l'on tape
 
Le fait d'avoir oublier l'* n'a pas l'air d'avoir une cause sur un éventuel seg fault car avec ou sans ça compile et ça s'éxécute.
J'ai executé en ne donnant aucun parametres puis plusieurs mais ça ne donne toujours pas de seg fault, c'est bizzare

Reply

Marsh Posté le 07-08-2006 à 17:12:21    

franceso a écrit :

Je pense que c'est la seule syntaxe valide pour exprimer le cast vers un type fonction.


C'est juste un cast je pense, parce que la fonction de tri accepte des void* et non des const char*, comme strcmp().

Message cité 1 fois
Message édité par Elmoricq le 07-08-2006 à 17:12:55
Reply

Marsh Posté le 07-08-2006 à 18:20:08    

Il faudrait peut-être libérer la mémoire allouée en fin de programme il me semble (mais ça ne provoque pas d'erreur de segmentation).

Reply

Marsh Posté le 07-08-2006 à 18:53:23    

Elmoricq a écrit :

C'est juste un cast je pense, parce que la fonction de tri accepte des void* et non des const char*, comme strcmp().


J'ai essayé en mettant :

Code :
  1. void bubbleSort(char **tab, int (*cmp)(char *, char *))

et

Code :
  1. bubbleSort(t, (int (*)(void *, void *))&strcmp)


 
Normalement, je pensais que dans ce cas le cast explicite n'était pas obligatoire puisque strcmp est déjà une fonction du bon type, mais le compilateur donne quand même un warning. Etrange :/

Message cité 1 fois
Message édité par franceso le 07-08-2006 à 18:53:41

---------------
TriScale innov
Reply

Marsh Posté le 07-08-2006 à 19:07:16    

Gattuso a écrit :

Le fait d'avoir oublier l'* n'a pas l'air d'avoir une cause sur un éventuel seg fault car avec ou sans ça compile et ça s'éxécute.


 
effectivement, dans les deux cas ça compile (normal puisque le prof a brouillé les pistes en donnant à la fonction de comparaison un type (void*,void*)->int qui peut accepter n'importe quoi comme paramètre).
 
Par contre, je pense que le fait que tout s'exécute bien est un gros coup de chance. Théoriquement, la fonction strcmp pourrait bien faire n'importe quoi (y compris des erreurs de segmentations si elle parcourt ce qu'elle pense être des chaines de caractères en cherchant désespérément un 0 final qu'elle n'a aucune raison de trouver).
 
Dans notre cas particulier, il se trouve qu'on est sur que *p1 != *p2 (puisque *p1 et *p2 sont les adresses de deux chaines de caractères différentes) donc lorsque strcmp compare ce qu'il pense être le premier caractère de chaque chaine, on compare deux valeurs débiles mais qui sont nécéssairement différentes donc strcmp renvoit tout de suite un résultat. Du coup, je pense que jamais on n'obtiendra de segfault avec ce programme, bien qu'il fasse n'importe quoi avec des pointeurs.


---------------
TriScale innov
Reply

Marsh Posté le 07-08-2006 à 19:15:03    

T1, l'examen d'obfuscated C code... [:k-nar]


Message édité par farib le 07-08-2006 à 19:15:14

---------------
Bitcoin, Magical Thinking, and Political Ideology
Reply

Marsh Posté le 07-08-2006 à 20:02:44    

bubbleSort devrai prendre un 'int (*)(const char *, const char *)'
 
cast inutiles des malloc
 
l=(unsigned int)argc-1U; ??
-->
l=argc-1;
 
for(i=0U; i<l; ++i)
-->
for(i=0; i<l; i++) /* pourquoi faire autrement ? */
 
manque des const
 
la mémoire allouée dynamiquement n'est pas libérée (attention à la gestion des erreur)
 
printf("\n" );
-->
putchar('\n');


Message édité par skelter le 07-08-2006 à 20:03:05
Reply

Marsh Posté le 07-08-2006 à 21:22:01    

franceso a écrit :

J'ai essayé en mettant :

Code :
  1. void bubbleSort(char **tab, int (*cmp)(char *, char *))

et

Code :
  1. bubbleSort(t, (int (*)(void *, void *))&strcmp)


 
Normalement, je pensais que dans ce cas le cast explicite n'était pas obligatoire puisque strcmp est déjà une fonction du bon type, mais le compilateur donne quand même un warning. Etrange :/


 
Ca marche très bien sans cast si tu mets des const char* au prototype de la fonction plutôt que des char* ;)

Reply

Marsh Posté le 08-08-2006 à 09:08:43    

efefctivement, j'avais oublié les const :sweat:


---------------
TriScale innov
Reply

Marsh Posté le 09-08-2006 à 23:00:07    

Sve@r a écrit :

Beaucoup préfèrent mettre "++i" qui est plus rapide que "i++"...


 
Demain je zieute le code assembleur entre les deux pour vérifier. [:fou]

Reply

Marsh Posté le 09-08-2006 à 23:19:37    

je pense que le compilo corrige lorsqu'il n'y a qu'une instruction. A vérifier

Reply

Marsh Posté le 10-08-2006 à 01:02:37    

rien ne dit ca mais la plupart des compilo le font certainement, faut pas avoir inventé l'eau chaude
en gros ca ne sert a rien d'ecrire ++i a la place de i++ dans le seul but d'eviter la temp, il faut simplement utiliser l'un ou l'autre en fonction de la sémantique voulue
 
c'est en C++ qu'il faut faire attention, pour les types non-builtin, on peut surcharger ++ sans garantir la corrélation entre ++ post et pre donc le compilo ne peux pas optimiser

Reply

Marsh Posté le 10-08-2006 à 08:49:57    

on peux surcharger les deux non ?
 
operator++ ();    // prefix ++
operator++ (int); // postfix ++

Reply

Marsh Posté le 10-08-2006 à 10:21:56    

ben oui, et tu peux les implémenter comme tu veux. la surcharge d'opérateur est libre en C++, on doit juste respecter le nombre d'opérande.
comme tu n'est pas obligé d'implémenter ++ post et pre de telle sorte que r++ <=> temp = r, ++r, temp et ++r <=> r += 1 faut surtout pas s'attendre à ce que le compilateur fasse ce genre d'optimisation.
 
on peut remarquer que le langage D ne permet de surcharger que ++ pre et garanti ces relations sémantiques de base, ce qui rend possible ce genre d'optimisation pour n'importe quel type surchargeant ++

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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