prob C étrange : programme qui marche et personne ne comprend pourquoi

prob C étrange : programme qui marche et personne ne comprend pourquoi - C++ - Programmation

Marsh Posté le 16-09-2002 à 22:44:26    

Reply

Marsh Posté le 16-09-2002 à 22:44:26   

Reply

Marsh Posté le 16-09-2002 à 22:46:42    

Tu pourrais au moins retaper le sujet ici :sarcastic:


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 16-09-2002 à 22:47:53    

bonsoir tout le monde,  
 
voilà j'ai un petit problème avec le simple code suivant. Le programme marche parfaitement bien mais beaucoup de dév trouvent le code incorrect et ne comprennent pourquoi ça marche ! un avis ? le code est-il bon ? sinon que faudrait-il modifier pour le "purifier" ?  
 
merci :  
 
 
mention.h :  
 
 
 
# include <stdio.h>  
 
void laMention(void) ;  
 
float demanderNote(char commentaire[]) ;  
 
char* definirMention(float note) ;  
 
void afficherResultat(float note, char mention[]) ;  
 
 
 

Code :
  1. -----------------------------------------------------------
  2. mention.c :
  3. # include "mention.h"
  4. void laMention(void)
  5. {
  6. float note ;
  7. char *mention ;
  8. note = demanderNote("Entrez la note" ) ;
  9. if (note < 0 || note > 20)
  10. fprintf(stdout, "Erreur :\n\nNote invalide, merci d'entrer une note comprise dans l'intervalle [0, 20]." ) ;
  11. else
  12. {
  13. mention = definirMention(note) ;
  14. afficherResultat(note, mention) ;
  15. }
  16. }
  17. float demanderNote(char commentaire[])
  18. {
  19. float noteEntree ;
  20. fprintf(stdout, "%s : ", commentaire) ;
  21. fscanf(stdin, "%f", ¬eEntree) ;
  22. return noteEntree ;
  23. }
  24. char* definirMention(float note)
  25. {
  26. char *mentionCorrespondante;
  27. if (note >= 16)
  28. mentionCorrespondante = "Tres bien" ;
  29. else if (note >= 14)
  30. mentionCorrespondante = "Bien" ;
  31. else if (note >= 12)
  32. mentionCorrespondante = "Assez-bien" ;
  33. else if (note >= 10)
  34. mentionCorrespondante = "Passable" ;
  35. else
  36. mentionCorrespondante = "Echec" ;
  37. return mentionCorrespondante ;
  38. }
  39. void afficherResultat(float note, char mention[])
  40. {
  41. fprintf(stdout, "note : %5.2f\nmention : %s", note, mention);
  42. }
  43. --------------------------------------------------------------------------
  44. mentionTest.c :
  45. # include "mention.c"
  46. void main(void)
  47. {
  48. laMention() ;
  49. }


Message édité par zluman le 17-09-2002 à 13:41:48
Reply

Marsh Posté le 16-09-2002 à 22:51:22    

je vois pas de blème


---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 16-09-2002 à 22:52:36    

des dév me disent que ça coince au niveau des pointeurs

Reply

Marsh Posté le 16-09-2002 à 22:54:49    

ba non
à la limite tu pourrais déclarer en const char*


---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 16-09-2002 à 22:58:42    

ah ok ben cool alors si le code est correct :)
 
qques propos de dév :
 
<< erreur dans cette fonction :)  
char* definirMention(float note)
 
quoi que ça doit passer vue que c'est un char* mais j'ai un doute
car tu déclares dans ta fonction et donc à la sortie de la fonction la zone de pile est vidée
mais bon un char * c'est comme un int donc il doit renvoyer son adresse et du coup ça marche  
par contre si c'etait un char[2] par exemple, ça marcherait plus
>>
 
 
 
<< un char* c'est un int qui pointe vers une zone mémoire  
comme tu ne l'as pas initialisé ça pointe n'importe où
donc ton programme tombe en marche
un char * = une chaine statique  
ça marche pas c'est clair >>
 
 
et pourtant ...

Reply

Marsh Posté le 17-09-2002 à 00:35:08    

pour moi ca renvoie l'adresse mémoire contenant la chaine de caractère donc c'est correct (l'espace mémoire necessaire pour les chaines étant alloué à la compil)


Message édité par joce le 17-09-2002 à 00:36:10

---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 17-09-2002 à 09:05:29    

zluman a écrit a écrit :

 
[...]
char* definirMention(float note)  
{  
 
char *mentionCorrespondante;  
 
if (note >= 16)  
mentionCorrespondante = "Tres bien" ;  
else if (note >= 14)  
mentionCorrespondante = "Bien" ;  
else if (note >= 12)  
mentionCorrespondante = "Assez-bien" ;  
else if (note >= 10)  
mentionCorrespondante = "Passable" ;  
else  
mentionCorrespondante = "Echec" ;  
 
return mentionCorrespondante ;  
 
}  
[...]




 
Ben y'a pas de truc louche ...
Par contre je trouve que la presentation du code est bof ...

Code :
  1. -----------------------------------------------------------
  2. mention.c :
  3. # include "mention.h"
  4. void laMention(void)
  5. {
  6. float  note=0.0;
  7. char*  mention=NULL;
  8. note = demanderNote("Entrez la note" );
  9. if ( (note < 0) || (note > 20) )
  10.   {
  11.    fprintf(stdout, "Erreur :\n\nNote invalide, merci d'entrer une note comprise dans l'intervalle [0, 20]." );
  12.   }
  13. else
  14.   {
  15.    mention = definirMention(note);
  16.    afficherResultat(note, mention);
  17.   }
  18. }
  19. float demanderNote(char commentaire[])
  20. {
  21. float noteEntree=0.0;
  22. fprintf(stdout, "%s : ", commentaire);
  23. fscanf(stdin, "%f", ¬eEntree);
  24. return noteEntree;
  25. }
  26. char* definirMention(float note)
  27. {
  28. if (note >= 16) return "Tres bien";
  29. if (note >= 14) return "Bien";
  30. if (note >= 12) return "Assez-bien";
  31. if (note >= 10) return "Passable";
  32. return "Echec";
  33. }
  34. void afficherResultat(float note, char mention[])
  35. {
  36. fprintf(stdout, "note : %5.2f\nmention : %s", note, mention);
  37. }
  38. --------------------------------------------------------------------------
  39. mentionTest.c :
  40. # include "mention.c"
  41. void main(void)
  42. {
  43. laMention();
  44. }


---------------
Le site de l'année :D (XHTML 1.0 strict) : http://darkoli.free.fr/index.html
Reply

Marsh Posté le 17-09-2002 à 09:07:17    

joce a écrit a écrit :

pour moi ca renvoie l'adresse mémoire contenant la chaine de caractère donc c'est correct (l'espace mémoire necessaire pour les chaines étant alloué à la compil)




+1 (Comme Joce il a dit ...)


---------------
Le site de l'année :D (XHTML 1.0 strict) : http://darkoli.free.fr/index.html
Reply

Marsh Posté le 17-09-2002 à 09:07:17   

Reply

Marsh Posté le 17-09-2002 à 09:39:16    

Peut-etre que tes devs pensaient que les chaines "Tres bien" et compagnie etaient des variables locales.
Hors ce sont grosso-modo des variables globales, donc ca marche

Reply

Marsh Posté le 17-09-2002 à 10:00:30    

Justement sur cette question, pourrais-je avoir plus de détails ?
Personellement j'aurais dit que cela aurait pu poser un problème...

Reply

Marsh Posté le 17-09-2002 à 10:32:57    

Le seul problème que je vois à ce code, outre sa présentation déplorable, bien sûr -- mais je ne vais pas m'apesentir là-dessus, darkoli en a déjà parlé -- ce sont les affectations de chaînes de caractères :

Code :
  1. char *mentionCorrespondante; 
  2. mentionCorrespondante = "Tres bien" ;


En C strict, cette ligne ne fonctionne pas. Cependant, elle fonctionne correctement avec la plupart des compilateurs C++ actuels. Mais sache que ce n'est pas 100 % portable.
 
Qu'est-ce qui cloche ici ?
En théorie, en exécutant cette ligne, le compilateur va créer une chaîne de caractères temporaire pour stocker la chaîne constante "Tres bien", puis, il va faire pointer mentionCorrespondante vers le début de la zone mémoire qui contient cette chaîne de caractères. Enfin, la chaîne temporaire étant, justement temporaire, le compilateur pourra désallouer la mémoire qui a été réservée pour cette chaîne temporaire, et mentionCorrespondante va se retrouver à pointer vers une zone mémoire non allouée.
 
Comment résoudre le problème ? Faire toujours appel à strcpy() pour copier une chaine constante dans une variable de type chaine de caractères. Ce qui signifie également qu'il faut préalablement et explicitement allouer de la mémoire pour mentionCorrespondante avec un malloc().
Note : quand le code que tu as donné marche, c'est en fait le compilateur a transformé l'affectation en un strcpy() en douce.
 
Autre solution, pour ton cas précis, qui est la conséquence d'une règle totalement différente : éviter les chaînes de caractères "codées en dur" disséminées dans le code. Il est grandement préférable de les rassembler à un endroit précis du code. Par exemple, en définissant une table des chaînes constantes plus ou moins globales (cela peut-être global à un module plutôt qu'au programme entier). Ainsi, on aurait, dans le fichier mention.c :

Code :
  1. // Pour la lisibilité.
  2. #define  ARRAY_LENGTH(array)  (sizeof(array) / sizeof((array)[0]))
  3. // Ainsi les chaînes de caractères constantes sont allouées une
  4. // fois pour toutes par le compilateur, dès le début du  
  5. // programme, et elles existent jusqu'à sa fin.
  6. const char* mentions[]       = { "Echec", "Passable", "Assez bien", "Bien", "Tres bien" };
  7. int         seuil_mentions[] = { 0, 10, 12, 14, 16 };
  8. // Noter le nom de fonction plus approprié
  9. const char* donneMention(float note)
  10. {
  11.   int  index;
  12.   for (index = ARRAY_LENGTH(mentions) - 1; index >= 0; index--) {
  13.     if (note >= seuil_mentions[index]) {
  14.       return mentions[index];
  15.     }
  16.   }
  17.   return mentions[0];
  18. }


Message édité par BifaceMcLeOD le 17-09-2002 à 11:59:27
Reply

Marsh Posté le 17-09-2002 à 13:41:30    

DarkOli a écrit a écrit :

 
 
Ben y'a pas de truc louche ...
Par contre je trouve que la presentation du code est bof ...

Code :
  1. -----------------------------------------------------------
  2. mention.c :
  3. # include "mention.h"
  4. void laMention(void)
  5. {
  6. float  note=0.0;
  7. char*  mention=NULL;
  8. note = demanderNote("Entrez la note" );
  9. if ( (note < 0) || (note > 20) )
  10.   {
  11.    fprintf(stdout, "Erreur :\n\nNote invalide, merci d'entrer une note comprise dans l'intervalle [0, 20]." );
  12.   }
  13. else
  14.   {
  15.    mention = definirMention(note);
  16.    afficherResultat(note, mention);
  17.   }
  18. }
  19. float demanderNote(char commentaire[])
  20. {
  21. float noteEntree=0.0;
  22. fprintf(stdout, "%s : ", commentaire);
  23. fscanf(stdin, "%f", ¬eEntree);
  24. return noteEntree;
  25. }
  26. char* definirMention(float note)
  27. {
  28. if (note >= 16) return "Tres bien";
  29. if (note >= 14) return "Bien";
  30. if (note >= 12) return "Assez-bien";
  31. if (note >= 10) return "Passable";
  32. return "Echec";
  33. }
  34. void afficherResultat(float note, char mention[])
  35. {
  36. fprintf(stdout, "note : %5.2f\nmention : %s", note, mention);
  37. }
  38. --------------------------------------------------------------------------
  39. mentionTest.c :
  40. # include "mention.c"
  41. void main(void)
  42. {
  43. laMention();
  44. }






T'avais pas besoin de te faire chier à faire la tabulation la balise cpp la fait toute seule


---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 17-09-2002 à 13:45:07    

BifaceMcLeOD a écrit a écrit :

Le seul problème que je vois à ce code, outre sa présentation déplorable, bien sûr -- mais je ne vais pas m'apesentir là-dessus, darkoli en a déjà parlé -- ce sont les affectations de chaînes de caractères :

Code :
  1. char *mentionCorrespondante; 
  2. mentionCorrespondante = "Tres bien" ;


En C strict, cette ligne ne fonctionne pas. Cependant, elle fonctionne correctement avec la plupart des compilateurs C++ actuels. Mais sache que ce n'est pas 100 % portable.
 
Qu'est-ce qui cloche ici ?
En théorie, en exécutant cette ligne, le compilateur va créer une chaîne de caractères temporaire pour stocker la chaîne constante "Tres bien", puis, il va faire pointer mentionCorrespondante vers le début de la zone mémoire qui contient cette chaîne de caractères. Enfin, la chaîne temporaire étant, justement temporaire, le compilateur pourra désallouer la mémoire qui a été réservée pour cette chaîne temporaire, et mentionCorrespondante va se retrouver à pointer vers une zone mémoire non allouée.
 
Comment résoudre le problème ? Faire toujours appel à strcpy() pour copier une chaine constante dans une variable de type chaine de caractères. Ce qui signifie également qu'il faut préalablement et explicitement allouer de la mémoire pour mentionCorrespondante avec un malloc().
Note : quand le code que tu as donné marche, c'est en fait le compilateur a transformé l'affectation en un strcpy() en douce.
 
Autre solution, pour ton cas précis, qui est la conséquence d'une règle totalement différente : éviter les chaînes de caractères "codées en dur" disséminées dans le code. Il est grandement préférable de les rassembler à un endroit précis du code. Par exemple, en définissant une table des chaînes constantes plus ou moins globales (cela peut-être global à un module plutôt qu'au programme entier). Ainsi, on aurait, dans le fichier mention.c :

Code :
  1. // Pour la lisibilité.
  2. #define  ARRAY_LENGTH(array)  (sizeof(array) / sizeof((array)[0]))
  3. // Ainsi les chaînes de caractères constantes sont allouées une
  4. // fois pour toutes par le compilateur, dès le début du  
  5. // programme, et elles existent jusqu'à sa fin.
  6. const char* mentions[]       = { "Echec", "Passable", "Assez bien", "Bien", "Tres bien" };
  7. int         seuil_mentions[] = { 0, 10, 12, 14, 16 };
  8. // Noter le nom de fonction plus approprié
  9. const char* donneMention(float note)
  10. {
  11.   int  index;
  12.   for (index = ARRAY_LENGTH(mentions) - 1; index >= 0; index--) {
  13.     if (note >= seuil_mentions[index]) {
  14.       return mentions[index];
  15.     }
  16.   }
  17.   return mentions[0];
  18. }






tout à fait d'accord :jap:


---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 17-09-2002 à 13:46:21    

Là OK, je comprend mieux ! ;)

Reply

Marsh Posté le 17-09-2002 à 14:27:48    

joce a écrit a écrit :

 
T'avais pas besoin de te faire chier à faire la tabulation la balise cpp la fait toute seule




D'ailleurs quand la tabulation est faite, la balise CPP merde !!! (Et comme en général mon code est indenté comme je le poste je ne vais pas le dé-indenter avant !!!).


---------------
Le site de l'année :D (XHTML 1.0 strict) : http://darkoli.free.fr/index.html
Reply

Marsh Posté le 17-09-2002 à 14:30:43    

BifaceMcLeOD a écrit a écrit :

Le seul problème que je vois à ce code, outre sa présentation déplorable, bien sûr -- mais je ne vais pas m'apesentir là-dessus, darkoli en a déjà parlé -- ce sont les affectations de chaînes de caractères :

Code :
  1. char *mentionCorrespondante; 
  2. mentionCorrespondante = "Tres bien" ;


En C strict, cette ligne ne fonctionne pas. Cependant, elle fonctionne correctement avec la plupart des compilateurs C++ actuels. Mais sache que ce n'est pas 100 % portable.
 
[...]
 
Comment résoudre le problème ? Faire toujours appel à strcpy() pour copier une chaine constante dans une variable de type chaine de caractères. Ce qui signifie également qu'il faut préalablement et explicitement allouer de la mémoire pour mentionCorrespondante avec un malloc().
Note : quand le code que tu as donné marche, c'est en fait le compilateur a transformé l'affectation en un strcpy() en douce.
 
[...]
 




Mais dans ce cas ça ne fonctionne pas car la chaine destinatrice de la copie n'existe pas puisque que c'est un pointeur. Non ? Ou je dis n'importe quoi ?


---------------
Le site de l'année :D (XHTML 1.0 strict) : http://darkoli.free.fr/index.html
Reply

Marsh Posté le 17-09-2002 à 14:35:05    

DarkOli a écrit a écrit :

 
Mais dans ce cas ça ne fonctionne pas car la chaine destinatrice de la copie n'existe pas puisque que c'est un pointeur. Non ? Ou je dis n'importe quoi ?




 
j'avais pas vu la note, c nimportequoi. Si ça marche c par ce que le compilo ne crée pas de chaine temporaire. La chaîne exite en dehors du cadre de la fonction et l'adresse passée en retour est donct tout à fait valide.


---------------
Le Tyran
Reply

Marsh Posté le 17-09-2002 à 15:34:44    

LetoII a écrit a écrit :

 
 
j'avais pas vu la note, c nimportequoi. Si ça marche c par ce que le compilo ne crée pas de chaine temporaire. La chaîne exite en dehors du cadre de la fonction et l'adresse passée en retour est donct tout à fait valide.




 
Voilà c'est ça. En gros les chaînes en dur dans le code sont comme des variables globales donc le programme se contente de filer l'adresse memoire de la chaine. :D C'est mieux comme ça.


---------------
Le site de l'année :D (XHTML 1.0 strict) : http://darkoli.free.fr/index.html
Reply

Marsh Posté le 17-09-2002 à 17:42:38    

BifaceMcLeOD a écrit a écrit :

 
En C strict, cette ligne ne fonctionne pas. Cependant, elle fonctionne correctement avec la plupart des compilateurs C++ actuels. Mais sache que ce n'est pas 100 % portable.




 
Je ne suis pas un pro des standards, mais dans un de mes bouquins (Exceptional C++), l'auteur dit qu'il y a plusieurs zones memoires:
- stack
- variables globales
- heap
- free store
- et... donnees constantes
 
Si j'y pense, je jetterai un coup d'oeil dans ce bouquin chez moi ce soir.

Reply

Marsh Posté le 18-09-2002 à 03:22:54    

joce a écrit a écrit :

T'avais pas besoin de te faire chier à faire la tabulation la balise cpp la fait toute seule


Tiens justement, je voulais t'en parler.
J'aime pas ça.
1) Elle est boguée pour certains trucs.
2) J'indente/alligne toujours correctement mon code, à MA façon.
 
Il pourrait pas y avoir au moins une option pour désactiver ça ?


---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone
Reply

Marsh Posté le 18-09-2002 à 03:24:55    

Il est presque normal que ce programme marche.
 
Pas forcément compilable:

Code :
  1. void main() /*Pas standard*/
  2. int main(void){ /*standard*/
  3. /*...*/
  4. return 0;
  5. }


Les chaînes littérales sont constantes, il vaudrait avoir des 'const char*', mais cela oblige à changer le code:

Code :
  1. const char* definirMention(float note)
  2. {
  3. const char* mentions[]= {
  4.  "Tres bien",
  5.  "Bien",
  6.  "Assez-bien",
  7.  "Passable",
  8.  "Echec"
  9. }
  10. int iMention;
  11.      if (note >= 16) iMention= 0 ;
  12. else if (note >= 14) iMention= 1 ;
  13. else if (note >= 12) iMention= 2 ;
  14. else if (note >= 10) iMention= 3 ;
  15. else                 iMention= 4 ;
  16. return mentions[iMention] ;
  17. }

Ou alors le tableau est plus global, et on renvoie juste l'indice.
Je ne suis pas du tout partisan de la copie inutile dans tous les sens: lenteur + bogues.
Je confirme que les chaînes littérales sont des tableaux globaux/statiques.
Pas de problème d'allocation donc.
 
Compilable, mais super moche:

Code :
  1. # include "mention.c"

On inclus des headers.
inclure des sources, ça ne se fait pas. Ou alors on a de *TRES* bonnes raisons.
 
Correct, mais inutile:

Code :
  1. fprintf(stdout... //on apelles ça printf
  2. fscanf(stdin... ///on apelles ça scanf


Conception
Ça est bien compliqué et long pour pas grand-chose.
Le header devrait être protégé comme indiqué. Sauf qu'il me semble que les noms commençant par "__" ou  "_" sont réservés au système.
C'est demanderNote qui devrait tester la validité, et si elle est invalide, au choix:
-redemmander
-renvoyer une valeur d'erreur à tester


Message édité par Musaran le 18-09-2002 à 03:26:04

---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone
Reply

Marsh Posté le 18-09-2002 à 09:38:11    

Musaran a écrit a écrit :

 
1) Elle est boguée pour certains trucs.
2) J'indente/alligne toujours correctement mon code, à MA façon.
 
Il pourrait pas y avoir au moins une option pour désactiver ça ?




 
1) ouais :/
2) y a fixed au lieu de code alors...
 


if machin = truc then
  bidule
else  
begin
  a := 5;
  if test then
    chose(a);
end;


 
PS: Joce, on attend tj la coloration / mise en gras des mots clé pour le Pascal :D vu que t'as viré la balise [pascal] j'imagine que c'est foutu pour ça ? Et qu'en est-il de [php] qui marchait pas trop mal ? (à part un immense bug :D)


Message édité par antp le 18-09-2002 à 09:42:09

---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 18-09-2002 à 17:10:06    

BifaceMcLeOD a écrit a écrit :

Le seul problème que je vois à ce code, outre sa présentation déplorable, bien sûr -- mais je ne vais pas m'apesentir là-dessus, darkoli en a déjà parlé -- ce sont les affectations de chaînes de caractères :

Code :
  1. char *mentionCorrespondante; 
  2. mentionCorrespondante = "Tres bien" ;


En C strict, cette ligne ne fonctionne pas. Cependant, elle fonctionne correctement avec la plupart des compilateurs C++ actuels. Mais sache que ce n'est pas 100 % portable.
 
Qu'est-ce qui cloche ici ?
En théorie, en exécutant cette ligne, le compilateur va créer une chaîne de caractères temporaire pour stocker la chaîne constante "Tres bien", puis, il va faire pointer mentionCorrespondante vers le début de la zone mémoire qui contient cette chaîne de caractères. Enfin, la chaîne temporaire étant, justement temporaire, le compilateur pourra désallouer la mémoire qui a été réservée pour cette chaîne temporaire, et mentionCorrespondante va se retrouver à pointer vers une zone mémoire non allouée.

 
Comment résoudre le problème ? Faire toujours appel à strcpy() pour copier une chaine constante dans une variable de type chaine de caractères. Ce qui signifie également qu'il faut préalablement et explicitement allouer de la mémoire pour mentionCorrespondante avec un malloc().
Note : quand le code que tu as donné marche, c'est en fait le compilateur a transformé l'affectation en un strcpy() en douce.
 
Autre solution, pour ton cas précis, qui est la conséquence d'une règle totalement différente : éviter les chaînes de caractères "codées en dur" disséminées dans le code. Il est grandement préférable de les rassembler à un endroit précis du code. Par exemple, en définissant une table des chaînes constantes plus ou moins globales (cela peut-être global à un module plutôt qu'au programme entier). Ainsi, on aurait, dans le fichier mention.c :

Code :
  1. // Pour la lisibilité.
  2. #define  ARRAY_LENGTH(array)  (sizeof(array) / sizeof((array)[0]))
  3. // Ainsi les chaînes de caractères constantes sont allouées une
  4. // fois pour toutes par le compilateur, dès le début du  
  5. // programme, et elles existent jusqu'à sa fin.
  6. const char* mentions[]       = { "Echec", "Passable", "Assez bien", "Bien", "Tres bien" };
  7. int         seuil_mentions[] = { 0, 10, 12, 14, 16 };
  8. // Noter le nom de fonction plus approprié
  9. const char* donneMention(float note)
  10. {
  11.   int  index;
  12.   for (index = ARRAY_LENGTH(mentions) - 1; index >= 0; index--) {
  13.     if (note >= seuil_mentions[index]) {
  14.       return mentions[index];
  15.     }
  16.   }
  17.   return mentions[0];
  18. }






 
Je suis assez surprise par ce que tu dis...
 
En effet le Kernighan & Ritchie n'est pas du tout du meme avis que toi.
 
D'apres ce livre (2nd edition C ansi A2.6 & 5.5) une constante chaine de caracteres à une classe de stockage static (donc loin d'etre temporaire) et l'affecter à un pointeur fait que ce pointeur pointe sur cette chaine static.
 
Il n'est absolument pas fait metion d'une quelconque chaine temporaire...
 
Par contre modifier une telle chaine est annoncé comme indefini. Ce qui infirme encore la possibilité d'une chaine temporaire.
 
A propos du strcpy, le strdup permet de faire en un étape l'allocation et la copie.


Message édité par BENB le 18-09-2002 à 17:12:33
Reply

Marsh Posté le 18-09-2002 à 17:14:09    

BENB a écrit a écrit :

Par contre modifier une telle chaine est annoncé comme indefini.


haaaa, le mot magique de toute spécification qui se respecte ! :D

Reply

Marsh Posté le 18-09-2002 à 17:23:02    

youdontcare a écrit a écrit :

haaaa, le mot magique de toute spécification qui se respecte ! :D




 
Le plus probable est qu'elle soit modifiée definitivement jusqu'à la fin de l'execution du programme, mais sachant que le compilo à le droit de reunir plusieurs chaines identiques modifier une chaine peut en modifier une autre ailleurs (identique), les conséquenses sont donc bien indéfinies...


Message édité par BENB le 18-09-2002 à 17:23:40
Reply

Marsh Posté le 18-09-2002 à 17:26:16    

BENB a écrit a écrit :

 
 
Le plus probable est qu'elle soit modifiée definitivement jusqu'à la fin de l'execution du programme, mais sachant que le compilo à le droit de reunir plusieurs chaines identiques modifier une chaine peut en modifier une autre ailleurs (identique), les conséquenses sont donc bien indéfinies...




 
Ben non, puis que ça dépend du compilo :D


---------------
Le Tyran
Reply

Marsh Posté le 18-09-2002 à 17:37:25    

BENB a écrit a écrit :

les conséquenses sont donc bien indéfinies...


vi, bien que l'approche que tu cites est la plus logique d'un point de vue implémentation. mais voir 'indéfini' me donne toujours l'impression d'un "on n'est pas allé au bout des choses" (impression certainement erronée, mais qui me titille toujours).

Reply

Marsh Posté le 18-09-2002 à 17:49:12    

Leto II > Non indefini n'est pas forcement "implementation dependant". Ca peut l'etre, mais pas forcement.
 
J'ai bien commencé mon post par "Le plus probable", et je montre que pour un implementation définie, le resultat est indéfini, c'est à dire que la modification d'une chaine a un endroit donné peut provoquer de modifications de comportement du programme ailleurs.  
 
Après rien n'empeche l'implémentation d'etre différente que celle que je suppose, et donc que les modifications aient des conséquences différentes que celles que je suppose...
 
Bien souvent le terme indefini laisse supposer (comme le confirme youdontcare) qu'on ne c'est pas posé la question. Bien souvent au contraire cette affirmation est forte est sous-entends que les conséquences peuvent affecter le fonctionnement de l'application au-dela de ce qui était prévisible par des effets de bord que l'utilisateur n'est pas sensé connaitre.
 
C'est bien plus grave qu'un resultat "implementation dependant" qui lui est supposé etre constant pour une implementation donnée, et qui peut donc etre vérifé par un test...

Reply

Marsh Posté le 18-09-2002 à 18:17:01    

BENB a écrit a écrit :

 
En effet le Kernighan & Ritchie n'est pas du tout du meme avis que toi.




Le seul hic, c'est que bien peu de compilateurs respectent ce standard historique : la plupart respectent la norme ANSI, qui comportent pas mal de différences assez subtiles avec le standard K&R (mais on est en plein dans la subtilité, là, n'est-ce pas ?  ;) ).
 
A part ça, je peux te garantir que ce que je décris, c'est du vécu. Avant, moi aussi, je faisais des affectations directes. Jusqu'au jour où j'ai eu des bugs méchamment subtils et méchamment balèzes à trouver (qui datent d'il y a une petite dizaine d'années, je reconnais). Et depuis, je fais des strcpy(), ou mieux, des tables de caractères statiques.
 
PS: J'avoue que je n'aime pas trop les strdup(). C'est une fonction qui fait 2 choses en une, et je préfère faire une allocation explicite (comme ça, c'est plus facile de compter le nombre d'allocations et de désallocations de manière automatique, aussi ; donc de faire des vérifications dans la gestion mémoire). Et puis une fois sur 2, tu es en C++, et il n'est jamais très bon de mélanger les blocs mémoires alloués avec new et malloc() (et clairement, c'est très mauvais de désallouer par delete un bloc alloué par malloc() ; or strdup() fait un malloc() implicite)

Reply

Marsh Posté le 18-09-2002 à 18:22:30    

BifaceMcLeOD a écrit a écrit :

 
Le seul hic, c'est que bien peu de compilateurs respectent ce standard historique : la plupart respectent la norme ANSI, qui comportent pas mal de différences assez subtiles avec le standard K&R (mais on est en plein dans la subtilité, là, n'est-ce pas ?  ;) ).
 
A part ça, je peux te garantir que ce que je décris, c'est du vécu. Avant, moi aussi, je faisais des affectations directes. Jusqu'au jour où j'ai eu des bugs méchamment subtils et méchamment balèzes à trouver (qui datent d'il y a une petite dizaine d'années, je reconnais). Et depuis, je fais des strcpy(), ou mieux, des tables de caractères statiques.
 
PS: J'avoue que je n'aime pas trop les strdup(). C'est une fonction qui fait 2 choses en une, et je préfère faire une allocation explicite (comme ça, c'est plus facile de compter le nombre d'allocations et de désallocations de manière automatique, aussi ; donc de faire des vérifications dans la gestion mémoire). Et puis une fois sur 2, tu es en C++, et il n'est jamais très bon de mélanger les blocs mémoires alloués avec new et malloc() (et clairement, c'est très mauvais de désallouer par delete un bloc alloué par malloc() ; or strdup() fait un malloc() implicite)




 
Je parlais bien de l'édition consacrée au C ansi...  ;)  
Je te donne d'ailleurs les references des chapitres concernés
 
Par contre les différences entre C ansi et C K&R ne tiennent pas de la subtilité à mon avis...


Message édité par BENB le 18-09-2002 à 18:23:37
Reply

Marsh Posté le 18-09-2002 à 19:39:00    

le coup du litteral instancie temporairement je trouve ca un peu tire par les cheveux et tres certainement vicieux
 
Et le surcout du strcpy aurait lieu a chaque appel de la fonction??
 
LeGreg

Reply

Marsh Posté le 18-09-2002 à 23:03:26    

youdontcare a écrit a écrit :

vi, bien que l'approche que tu cites est la plus logique d'un point de vue implémentation. mais voir 'indéfini' me donne toujours l'impression d'un "on n'est pas allé au bout des choses" (impression certainement erronée, mais qui me titille toujours).




 
bien sur que non, s'il est ecrit dans le standard que le comportement d'un code est indefini c'est qu'on a etudie ce cas et qu'on en a deduit qu'on pouvait ne pas le definir (il est le plus souvent incorrect d'ecrire du code qui a un comportement indefini, meme si ca compile). Si l'on n'etait vraiment pas alle "au bout des choses", on n'en aurait pas fait mention, ce qui n'est pas le cas.
 
Exemple: delete sur un pointeur non alloue. Le compilateur va te laisser faire, mais le comportement du programme ensuite va etre 'indefini': soit il ne fait rien de particulier (le cas le pire), soit il crashe sur l'instruction (le meilleur cas), soit il va provoquer une corruption de la memoire qui peut avoir n'importe quel effet.
Si on avait affaire a un autre langage que le C++, on aurait pu definir dans le standard qu'appeler delete sur un pointeur non alloue ne fasse rien ou leve une exception par exemple mais cela aurait necessite un travail supplementaire et la simplicite du langage en aurait souffert.
(en java toute reference pointe toujours sur un objet valide, sauf si elle est mise explicitement a nil)
 
LeGreg

Reply

Marsh Posté le 18-09-2002 à 23:09:42    

un autre exemple de comportement indéfini : un goto qui saute à l'intérieur d'une boucle (venant de l'extérieur de la boucle)
du moins c'est comme ça en Pascal :

Citation :

Never jump into a loop or other structured statement, since this can have unpredictable effects.


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 18-09-2002 à 23:44:05    

Quand quelque chose est spécifié comme indéfini, ça veut dire qu'on y a bien pensé, qu'on a bien examiné les possibilités, mais qu'on préfères pour l'instant n'imposer aucune règle.
 
Je me rends compte qu'il y a moyen de faire beaucoup plus simple que ma proposition:

Code :
  1. const char* definirMention(float note)
  2. {
  3. if (note >= 16) return "Tres bien";
  4. if (note >= 14) return "Bien";
  5. if (note >= 12) return "Assez bien";
  6. if (note >= 10) return "Passable";
  7. /*noalign*/     return "Echec";
  8. }

L'apparence n'est pas ordinaire, mais c'est du code absolument standard, qui est en plus court et lisible.
 
De mon point de vue, copier ces chaînes serait une source de bogues (dépassement, non-libération, identité), et une complication inutile.


---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone
Reply

Marsh Posté le 19-09-2002 à 09:43:21    

Musaran a écrit a écrit :

Quand quelque chose est spécifié comme indéfini, ça veut dire qu'on y a bien pensé, qu'on a bien examiné les possibilités, mais qu'on préfères pour l'instant n'imposer aucune règle.
 
Je me rends compte qu'il y a moyen de faire beaucoup plus simple que ma proposition:

Code :
  1. const char* definirMention(float note)
  2. {
  3. if (note >= 16) return "Tres bien";
  4. if (note >= 14) return "Bien";
  5. if (note >= 12) return "Assez bien";
  6. if (note >= 10) return "Passable";
  7. /*noalign*/     return "Echec";
  8. }

L'apparence n'est pas ordinaire, mais c'est du code absolument standard, qui est en plus court et lisible.
 
De mon point de vue, copier ces chaînes serait une source de bogues (dépassement, non-libération, identité), et une complication inutile.




+1 (Comme ce que j'ai dit tout en haut :D)


---------------
Le site de l'année :D (XHTML 1.0 strict) : http://darkoli.free.fr/index.html
Reply

Marsh Posté le 19-09-2002 à 10:09:27    

Musaran a écrit a écrit :

Quand quelque chose est spécifié comme indéfini, ça veut dire qu'on y a bien pensé, qu'on a bien examiné les possibilités, mais qu'on préfères pour l'instant n'imposer aucune règle.
 
Je me rends compte qu'il y a moyen de faire beaucoup plus simple que ma proposition:
(...)
L'apparence n'est pas ordinaire, mais c'est du code absolument standard, qui est en plus court et lisible.
 
De mon point de vue, copier ces chaînes serait une source de bogues (dépassement, non-libération, identité), et une complication inutile.




Vous noterez quand même que ma proposition ne comportait aucune copie de chaîne, puisqu'elle utilisait une table de chaînes de caractères allouées statiquement...  ;)

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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