Questions d'un débutant en C...

Questions d'un débutant en C... - C - Programmation

Marsh Posté le 30-03-2006 à 14:02:56    

Alors voilà, je me suis maintenant bien attaqué au livre "Le langage C, norme ANSI, 2eme edition" de K&R...
J'en suis au début encore...
Et, dans cette édition, il y a des exercices à la fin de chaque sous chapitre, mais les corrections sont dans un autre livre (que je n'ai pas).
Donc, jen suis à l'exercice 1-6 et 1-7.
Je vous explique:
Il est dit précédemment que, dans un while

Code :
  1. (c = getchar()) != EOF)


n'est pas pareil que

Code :
  1. c = getchar() != EOF


 
Car dans le 2eme cas, la priorité est au !=, donc le test de relation != serait effectué avant l'affectation =. Ca, c'est bon, j'ai compris.
Mais c'est la suite où j'ai un peu du mal...
En effet, il est écrit que cette instruction a l'effet indésirable de mettre c à 0 ou à 1, selon que l'appel getchar a rencontré la fin de fichier ou pas.
Alors là déjà je ne comprends pas trop le sens... Si vous pouviez m'expliquer...  :)  
 
Et après, l'exercice, c'est de :
Exercice 1-6. Vérifiez que l'expression getchar() !=EOF vaut soit 0, soit 1.
J'ai pensé pour celà à utilisé un if (malgrès qu'il n'a pas encore été abordé jusqu'ici dans le livre), mais je ne sais pas trop comment le faire en fait. Pour info, à cet endroit du livre, seuls les while et for ont été abordés comme "opérations" (je ne sais pas si le therme est le bon), donc à mon avis il doit y avoir un moyen en utilisant un while ou for...
 
L'autre exercice est:
Exercice 1-7. Ecrivez un programme qui affiche la valeur de EOF.
J'ai essayé cela, et j'ai fini par faire ce programme :

Code :
  1. #include <stdio.h>
  2. main()
  3. {
  4.     int mini;
  5.     mini = EOF;
  6.     printf("%d", mini);
  7. }


Et ça m'affiche -1.
Sauf que, quand je remplace le %d par un %f, ça m'affiche 0 !
Comment cela se fait-il?
 
Voilà, merci :)
 
 
P.S. Pour les autres questions tout au long de ma lecture de ce livre, préférez-vous que je les pause à la suite de ce post ou que je cré des nouveaux posts?


Message édité par floboss07 le 30-03-2006 à 14:03:39
Reply

Marsh Posté le 30-03-2006 à 14:02:56   

Reply

Marsh Posté le 30-03-2006 à 14:58:50    

L'expression c = getchar() != EOF; est évaluée comme c = (getchar() != EOF );
 
Deux cas possibles

  • getchar() renvoie EOF en fin de fichier, le test getchar() != EOF est faux et donc renvoie 0.
  • getchar() renvoie une valeur différente de EOF, le test getchar() != EOF réussit et renvoie donc 1.

Pour ton programme

Code :
  1. #include <stdio.h>
  2. main()
  3. {
  4.     int mini;
  5.     mini = EOF;
  6.     printf(&#034;%d", mini);
  7. }

Pense que le prototype de main est soit

  • int main(void) si tu n'as pas besoin des arguments de la ligne de commande
  • int main (int argc, char **argv) si tu en as besoin.


La fonction main retourne un entier, soit 0, soit EXIT_SUCCESS soit EXIT_FAILURE


Message édité par Trap D le 30-03-2006 à 15:03:33
Reply

Marsh Posté le 30-03-2006 à 15:00:43    

Citation :

Code :
  1. c = getchar() != EOF

cette instruction a l'effet indésirable de mettre c à 0 ou à 1, selon que l'appel getchar a rencontré la fin de fichier ou pas.
Alors là déjà je ne comprends pas trop le sens... Si vous pouviez m'expliquer...  :)

A cause de la priorité des opérateurs,

Code :
  1. c = getchar() != EOF

est équivalent à

Code :
  1. c = (getchar() != EOF)

Le problème, c'est que l'évaluation de l'expression getchar() != EOF renvoie une valeur booléenne qui est tranformée en 0 ou 1 lorsque tu demandes de la stocker dans la variable entière c
 
 

Citation :

Exercice 1-6. Vérifiez que l'expression getchar() !=EOF vaut soit 0, soit 1.
J'ai pensé pour celà à utilisé un if (malgrès qu'il n'a pas encore été abordé jusqu'ici dans le livre), mais je ne sais pas trop comment le faire en fait. Pour info, à cet endroit du livre, seuls les while et for ont été abordés comme "opérations" (je ne sais pas si le therme est le bon), donc à mon avis il doit y avoir un moyen en utilisant un while ou for...

Je pense que ce qu'ils attendent de toi ici est tout simplement un truc du genre :

Code :
  1. int i = (getchar() != EOF);
  2. printf( "%d\n", i );


 
 

Citation :

Exercice 1-7. Ecrivez un programme qui affiche la valeur de EOF.
J'ai essayé cela, et j'ai fini par faire ce programme : ...

tu n'as pas mis la bonne signature pour main. Voici une version conforme à la norme:

Code :
  1. #include <stdio.h>
  2. int main() /* main() renvoie toujours un int */
  3. {
  4.   int mini;
  5.   mini = EOF;
  6.   printf("%d\n", mini);
  7.   return 0;
  8. }


 
 

Citation :

Sauf que, quand je remplace le %d par un %f, ça m'affiche 0 !

tu demandes d'afficher un float (%f) mais tu fournis à printf un argument de type int ! Pas étonnant qu'il fasse n'importe quoi. Normalement, ton compilateur a du te mettre un warning à cette ligne (si ce n'est pas le cas, tu devrais lui passer des options pour qu'il te donne plus de warnings).
Si tu veux, à la limite, tu peux faire

Code :
  1. printf( "%f\n", (double)mini );

et il t'affichera -1.000.


Message édité par franceso le 30-03-2006 à 15:01:18

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

Marsh Posté le 30-03-2006 à 15:06:03    

En C, l' évaluation de getchar() != EOF ne renvoie pas une valeur booléenne mais un entier 0 ou 1.  
En C tout ce qui n'est pas 0 est considéré comme vrai.

Reply

Marsh Posté le 30-03-2006 à 15:28:47    

Trap D a écrit :

En C, l' évaluation de getchar() != EOF ne renvoie pas une valeur booléenne mais un entier 0 ou 1.

OK, mes excuses : en C, le type booléen n'existe pas :jap:


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

Marsh Posté le 30-03-2006 à 16:22:49    

Ok merci beaucoup, je comprends déjà mieu...
Donc, si j'ai bien compris

Code :
  1. c = (getchar() != EOF)

donne à c la valeur 1 si getchar() est différent de EOF, et 0 si il est égal à EOF? (1)
Mais par contre, pour la "signature du main", je ne comprends pas ce que tu veux dire franceso... Dans mon livre, les programmes commencent toujours par

Code :
  1. main()

et non pas

Code :
  1. int main()

et ce livre respecte la norme ANSI...("le langage C, norme ANSI, 2e edition" )(2)
Et idem pour trap D, je ne comprend pas ce que tu veux dire quand tu dis

Citation :

Pense que le prototype de main est soit
 
    * int main(void) si tu n'as pas besoin des arguments de la ligne de commande
    * int main (int argc, char **argv) si tu en as besoin.  
 
 
La fonction main retourne un entier, soit 0, soit EXIT_SUCCESS soit EXIT_FAILURE


Car à vrai dire, là où j'en suis je n'ai pas encore vu de int main(void) ou autre (pour l'instant, la parenthèse était toujours vide (3), et d'ailleur, il n'y avait pas de int comme je l'ai dit précédemment).
Et en conclusion, je ne comprend donc pas pourquoi il m'affiche -1 en valeur de EOF... en fait, à quoi correspond EOF? Ce n'est pas censé représenté 0 justement?(4)
 
 
EDIT : J'ai numéroté chaque question distincte pour que ça soit un peu plus clair  :bounce:

Message cité 1 fois
Message édité par floboss07 le 30-03-2006 à 16:27:15
Reply

Marsh Posté le 30-03-2006 à 16:32:30    

4) EOF ne peut pas etre dans le rang d'un char (sinon comment savoir si getchar renvoi EOF ou un caractere lu sur stdout), et 0 est un caractere valide ('\0', caractere nul)
par contre l'entier -1 est hors du rang d'un char si un int est codé en 32bits + complément à deux pour les nombres négatifs: (unsigned int)(-1) == UINT_MAX > UCHAR_MAX

Reply

Marsh Posté le 30-03-2006 à 16:33:43    

EOF est une valeur réservée spéciale ayant la valeur -1. Cette valeur ne peut pas être confondue avec n'importe quel caractère pouvant être lu dans un fichier.
C'est pourquoi il est impératif que c soit un int, car avec un char, il pourrait y avoir confusion avec EOF.
Le livre de K&R est une référence c'est vrai mais qui date un peu, donc il faut se mettre à jour et utiliser la norme actuelle qui impose les prototype de main.

Reply

Marsh Posté le 30-03-2006 à 16:38:26    

Ok, merci.
Et, donc, comment faire pour que

Code :
  1. (getchar() != EOF)


=0
?
Car, avec ce programme :

Code :
  1. #include <stdio.h>
  2. main()
  3. {
  4.     int mini;
  5.     mini = (getchar() != EOF);
  6.     printf("%d", mini);
  7. }


Quelle que soit la touche sur laquelle j'appui, il m'affiche toujours 1... Pourtant je pensé qu'en entrant aucun caractère, juste en appuyant sur la touche entrée, ça mettrais 0..Mais en fait non.
 
EDIT : En clair, j'ai compris que getchar() = EOF est "l'indicateur de fin de fichier", mais je ne comprends pas à quoi ça correspond par rapport au clavié.. Enfin qu'est ce qu'il faut faire pour l'obtenir quoi..


Message édité par floboss07 le 30-03-2006 à 16:41:41
Reply

Marsh Posté le 30-03-2006 à 16:57:23    

Crtl D sous MicroSoft / DOS je crois.

Reply

Marsh Posté le 30-03-2006 à 16:57:23   

Reply

Marsh Posté le 30-03-2006 à 17:03:03    

2-3)  voici un extrait de la norme C90 (ISO/IEC 9899:1999)

Citation :

The function called at program startup is named main. The implementation declares no
prototype for this function. It shall be defined with a return type of int and with no
parameters:

Code :
  1. int main(void) { /* ... */ }

or with two parameters (referred to here as argc and argv, though any names may be
used, as they are local to the function in which they are declared):

Code :
  1. int main(int argc, char *argv[]) { /* ... */ }



le type de retour de la fonction main est toujours un entier. Il s'agit d'une valeur qui est renvoyée par ton programme au système d'exploitation. Les valeurs normalisées sont 0 (succès), EXIT_SUCCESS (succès) et EXIT_FAILURE (echec).
 
Si tu ne définis pas de type de retour pour ta fonction main, on suppose par défaut que c'est un int (et c'est pour ça que les exemples du livre sont quand même valides)
 
Si tu déclares ta fonction main avec deux arguments (par ex: int main(int argc, char**argv)) alors argv[0] ... argv[argc-1] sont des pointeurs vers des chaines de caractères contenant les jetons de la ligne de commande utilisée pour lancer le programme. Donc argv[0] contient le nom du programme, et argv[1] ... argv[argc-1] contiennent les arguments fournis au programme sur la ligne de commande.


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

Marsh Posté le 30-03-2006 à 17:07:54    

Trap D a écrit :

En C, l' évaluation de getchar() != EOF ne renvoie pas une valeur booléenne mais un entier 0 ou 1.


Un entier valant 0 ou 1 est très exactement un type booleen.
 


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 30-03-2006 à 17:11:28    

floboss07 a écrit :

Mais par contre, pour la "signature du main", je ne comprends pas ce que tu veux dire franceso... Dans mon livre, les programmes commencent toujours par

Code :
  1. main()

et non pas

Code :
  1. int main()

et ce livre respecte la norme ANSI...("le langage C, norme ANSI, 2e edition" )(2)


Ce livre est sorti juste avant la publication de la norme et s'appuyait sur les brouillons (drafts) de l'époque. Il y a eu des corrections plus tard :  
 
http://mapage.noos.fr/emdel/init_c.htm
 


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 30-03-2006 à 17:13:03    

franceso a écrit :

2-3)  voici un extrait de la norme C90 (ISO/IEC 9899:1999)


Si c'est xxx:1999, c'est C99 !

Message cité 1 fois
Message édité par Emmanuel Delahaye le 30-03-2006 à 17:14:29

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 30-03-2006 à 17:17:32    

Emmanuel Delahaye a écrit :

Un entier valant 0 ou 1 est très exactement un type booleen.


C'est un type au sens C ?

Reply

Marsh Posté le 30-03-2006 à 17:24:49    

Trap D a écrit :

C'est un type au sens C ?


C, non, mais au sens général, oui.
 


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 30-03-2006 à 17:25:39    

Trap D a écrit :

Crtl D sous MicroSoft / DOS je crois.


Ctrl-Z


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 30-03-2006 à 18:05:06    

Emmanuel Delahaye a écrit :

C, non, mais au sens général, oui.


On est bien d'accord  :)  
 
OK pour le Crtl Z, comme je ne peux pas tester actuellement ... :whistle:

Reply

Marsh Posté le 30-03-2006 à 18:13:46    

Emmanuel Delahaye a écrit :

Si c'est xxx:1999, c'est C99 !

:sweat: Oups, mon clavier a fourché!!!

Reply

Marsh Posté le 31-03-2006 à 13:50:22    

Bon, nouvelle question, mais j'vais rester sur le même sujet pour pas trop foutre le bordel lol...
 
La question cette fois c'est :
2crivez un programme qui compte les espaces, les tabulations et les fins de ligne.
 
J'ai donc créé celà (en me servant des exemple précédents du livre) :
 

Code :
  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.     int c, nl, nt, ne;
  5.     nl = 0;
  6.     nt = 0;
  7.     ne = 0;
  8.     while ((c = getchar()) != EOF)
  9.         if (c == '\n')
  10.             ++nl;
  11.         if (c == ' ')
  12.             ++ne;
  13.         if (c == '\t')
  14.             ++nt;
  15.         printf("Il y a" );
  16.         printf("%d", nl);
  17.         printf(" lignes, " );
  18.         printf("%d", nt);
  19.         printf("tabulation, et" );
  20.         printf("%d", ne);
  21.         printf(" espaces." );
  22. }


 
Mais, quoi que je fasse, ça me met toujours le bon nombre de lignes, mais 0 espaces et 0 tabulations...
Où ais-je fait une erreur?

Reply

Marsh Posté le 31-03-2006 à 13:55:40    

il ne faudrait pas encadrer tes "if" dans le "while" ? (utilisation de { })


Message édité par jlighty le 31-03-2006 à 13:55:58
Reply

Marsh Posté le 31-03-2006 à 14:06:38    

Merci, oui, c'était juste ça, erreur toute conne! :)

Reply

Marsh Posté le 31-03-2006 à 16:28:49    

Encore un petit problème :
Ecrivez un programme qui affiche son entrée à raison d'un mot par ligne.
 
J'ai créé celà :

Code :
  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.     int c, statut;
  5.     c = statut = 0;
  6.     while ((c = getchar()) != EOF){
  7.     if (c != ' ' || c != '\t' || c != '\n'){
  8.     statut = 1;
  9.     putchar(c);
  10. }
  11.     if (statut != 0 && (c == ' ' || c == '\t' || c == '\n')){
  12.     statut = 0;
  13.     putchar('\n');}
  14.     }
  15.   return 0;
  16. }


 
Sauf que, malgrès que j'ai mis un "statu" afin qu'une foi qu'il a sauté une ligne il n'en saute plus, si je met plusieurs espaces à la suite il saute plusieurs lignes. Comment cela se fait-il? J'ai surement du encore faire une petite erreur toute conne je suppose...


Message édité par floboss07 le 31-03-2006 à 16:29:21
Reply

Marsh Posté le 31-03-2006 à 16:40:28    

tu veux que la condition soit vraie uniquement dans le cas où c n'est ni ' ', ni '\t', ni '\n' => il faut mettre des 'et' (&& ) à la place des 'ou' (||) :  

Code :
  1. if (c != ' ' && c != '\t' && c != '\n')


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

Marsh Posté le 31-03-2006 à 16:42:49    

personnellement, j'aurais structuré ça un peu différemment :

Code :
  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.   int c, statut;
  5.   c = statut = 0;
  6.   while ((c = getchar()) != EOF){
  7.     if (c != ' ' && c != '\t' && c != '\n')
  8.       {
  9.         statut = 1;
  10.         putchar(c);
  11.       }
  12.     else if (statut != 0)
  13.       {
  14.         statut = 0;
  15.         putchar('\n');
  16.       }
  17.   }
  18.  
  19.   return 0;
  20. }


 
ça évite de tester deux fois si c est un espace, une tabulation ou un retour à la ligne.


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

Marsh Posté le 31-03-2006 à 16:44:19    

Lol, vraiment merci, comme je pensais c'était encore une petite erreur toute conne...
Peut-être qu'avec l'habitude j'arrêterais d'en faire...

Reply

Marsh Posté le 31-03-2006 à 16:48:28    

on peut faire nettement plus concis
 

Code :
  1. #include <stdio.h>
  2. #include <ctype.h>
  3. int main()
  4. {
  5.     int c;
  6.    
  7.     while( (c = getchar()) != EOF )
  8.     {
  9.         if( isspace(c) )
  10.             c = '\n';
  11.        
  12.         putchar(c);
  13.     }
  14.    
  15.     return 0;
  16. }

Reply

Marsh Posté le 31-03-2006 à 16:52:27    

Oui, mais je crois que Floboss07 voulait éviter les retours à la ligne multiples lorsqu'il y a plusieurs espaces à la suite.


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

Marsh Posté le 31-03-2006 à 16:55:01    

ha oui, ok

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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