Int et char sont dans un bateau
Résolu
Gouager
-
[Dal] Messages postés 6205 Date d'inscription Statut Contributeur Dernière intervention -
[Dal] Messages postés 6205 Date d'inscription Statut Contributeur Dernière intervention -
Bonjour,
Je m'arrache les cheveux, pas encore la tête, à essayer de comprendre pourquoi ce petit programme ne marche pas avec le type char , c'est à dire en remplaçant ce qui est en gras/ rouge par char et %c (désolé je ne sais pas comment faire pour bien vous présenter l'image du programme - je fais donc un copier/coller - si vous avez une méthode pour bien afficher les programmes je suis preneur)
Je pense que la variable nombre doit être int ou short int déjà compte tenu de la plage limitée du type char? Mais même en définissant nombre comme étant du type int ça ne fonctionne pas?!
Pour essayer une dernière fois d'être un peu clair:
en fait, je souhaiterais tester ce programme pour une plage restreinte de nombres entiers, par exemple la plage de -128 à +127 ce qui correspond, de ce que j'ai vu sur Internet, à la plage de valeur du type de données char
Donc je pensais définir nombre1 en char le nombre 2 en char et nombre en int
D'où ensuite ne plus utiliser %d mais %c dans le programme sauf pour la variable nombre qui reste %d.
Exemple:
nombre 1 = 123
nombre 2 = 10
nombre (donc l'addition)= 133
Je ne sais pas si je suis bien plus clair :)
Merci d'avance pour vos explications éclairées !
Cordialement
Je m'arrache les cheveux, pas encore la tête, à essayer de comprendre pourquoi ce petit programme ne marche pas avec le type char , c'est à dire en remplaçant ce qui est en gras/ rouge par char et %c (désolé je ne sais pas comment faire pour bien vous présenter l'image du programme - je fais donc un copier/coller - si vous avez une méthode pour bien afficher les programmes je suis preneur)
Je pense que la variable nombre doit être int ou short int déjà compte tenu de la plage limitée du type char? Mais même en définissant nombre comme étant du type int ça ne fonctionne pas?!
#include <stdio.h> #include <stdlib.h> main(int argc, char *argv[]) { int nombre=0,nombre1=0,nombre2=0; printf("saisir nombre1:\n"); scanf("%d",&nombre1); printf("saisir nombre2:\n"); scanf("%d",&nombre2); nombre = nombre1+nombre2; printf("%d+%d=%d",nombre1,nombre2,nombre); return 0; }
Pour essayer une dernière fois d'être un peu clair:
en fait, je souhaiterais tester ce programme pour une plage restreinte de nombres entiers, par exemple la plage de -128 à +127 ce qui correspond, de ce que j'ai vu sur Internet, à la plage de valeur du type de données char
Donc je pensais définir nombre1 en char le nombre 2 en char et nombre en int
D'où ensuite ne plus utiliser %d mais %c dans le programme sauf pour la variable nombre qui reste %d.
Exemple:
nombre 1 = 123
nombre 2 = 10
nombre (donc l'addition)= 133
Je ne sais pas si je suis bien plus clair :)
Merci d'avance pour vos explications éclairées !
Cordialement
A voir également:
- Int et char sont dans un bateau
- Simulateur bateau - Télécharger - Loisirs créatifs
- Coco char - Accueil - Réseaux sociaux
- Code de triche gta bateau - Guide
- Int converter - Télécharger - Bureautique
- Combien y a-t-il de bateaux dans la zone de 475 pixels de large et 1000 pixels de haut à partir du coin supérieur gauche de cette image ? - Guide
4 réponses
Salut,
Ton problème vient du fait que tu ne peux pas spécifier
Alors, la solution est d'utiliser un spécificateur de taille avec
en C89, cela marche donc mieux comme cela :
le spécificateur de taille
si tu tiens vraiment à utiliser des
http://www.cplusplus.com/reference/cstdio/scanf/
Dal
Ton problème vient du fait que tu ne peux pas spécifier
%ccar ce n'est pas un caractère que tu veux, mais un nombre décimal, et que si tu spécifies
%dsans autres précisions, c'est un int * qui doit être en paramètre.
Alors, la solution est d'utiliser un spécificateur de taille avec
%d.
en C89, cela marche donc mieux comme cela :
#include <stdio.h> int main(void) { short int nombre = 0; short int nombre1 = 0; short int nombre2 = 0; printf("saisir nombre1:\n"); scanf("%hd", &nombre1); printf("saisir nombre2:\n"); scanf("%hd", &nombre2); nombre = nombre1 + nombre2; printf("%d+%d=%d", nombre1, nombre2, nombre); return 0; }
%ddoit être utilisé, car ce que tu attends, c'est bien un nombre décimal, et pas un caractère
le spécificateur de taille
hpermet d'indiquer à scanf qu'il doit accueillir un
short int.
si tu tiens vraiment à utiliser des
char(des
signed charselon ce que tu dis), il te faudra utiliser du C99 et le spécificateur
hh, qui te permet de gérer des
signed charavec
%d.
http://www.cplusplus.com/reference/cstdio/scanf/
Dal
Dal à raison, scanf est un des plus complexes et dangereux, il faut contrôler ce quand passe à scanf, cependant tu peux également utilisé scanf avec les expressions pour ne vouloir ce que tu veux.
Mais il est préférable de créer une fonction par le quelle tu pourras contrôler ta saisie et en plus tu pourras les réutiliser dans d'autres projets.
Mais il est préférable de créer une fonction par le quelle tu pourras contrôler ta saisie et en plus tu pourras les réutiliser dans d'autres projets.
Ok.
Mais je pense que vu les programmes tout simple (une addition par exemple) que je rédige (ça fait seulement une semaine que j'apprends le langage C) scanf est suffisant. J'espère pouvoir le plus rapidement possible vous dire que j'arrive à m'en passer (après avoir créer ma propre fonction) :))
Enfin, peut être que bien comprendre les limites et la complexité de scanf permettra d'éviter d'autres erreurs de débutant, ou pas, par la suite sur d'autres sujets?
Gouager.
Mais je pense que vu les programmes tout simple (une addition par exemple) que je rédige (ça fait seulement une semaine que j'apprends le langage C) scanf est suffisant. J'espère pouvoir le plus rapidement possible vous dire que j'arrive à m'en passer (après avoir créer ma propre fonction) :))
Enfin, peut être que bien comprendre les limites et la complexité de scanf permettra d'éviter d'autres erreurs de débutant, ou pas, par la suite sur d'autres sujets?
Gouager.
@Gouager: bien comprendre scanf peut prendre du temps, mais te fera indéniablement progresser sur une multitude de sujets et comprendre beaucoup de finesses (ou de pièges selon les points de vue) du C. Ne te tracasse pas si tu ne comprend pas tout tout de suite, cela viendra.
@fiddy: pour une saisie sécurisée et avec un contrôle d'erreur de texte, scanf est effectivement utilisable, comme tu as pu me le montrer par le passé. Pour une saisie numérique, je ne trouve pas de moyen fiable de sécuriser une saisie sur le dépassement de capacité.
Que proposes-tu d'ajouter au code suivant :
pour éviter ceci :
comment sait-on si l'utilisateur n'a pas réellement tapé -31073 ? y a-t-il un autre contrôle d'erreur possible qui m'échappe (limiter la saisie en caractères ici n'aide pas vraiment) ?
ce sont ces difficultés qui me font préférer fgets et strtol pour valider une saisie numérique.
Dal
@fiddy: pour une saisie sécurisée et avec un contrôle d'erreur de texte, scanf est effectivement utilisable, comme tu as pu me le montrer par le passé. Pour une saisie numérique, je ne trouve pas de moyen fiable de sécuriser une saisie sur le dépassement de capacité.
Que proposes-tu d'ajouter au code suivant :
#include <stdio.h> #include <stdlib.h> #include <limits.h> int main(void) { short int nombre1 = 0; char c; int code; printf("Les valeurs acceptables pour un short int " "sont de %d à %d\n", SHRT_MIN, SHRT_MAX); printf("saisir nombre1:\n"); code = scanf("%hd", &nombre1); if (code != 1) { printf("Erreur, je n'ai pas pu lire 1 short int\n"); } if (code == EOF) { printf("Erreur : je n'ai rien pu lire\n"); code = -1; } if (feof(stdin) != 0) { printf("Erreur : le flux stdin s'est arrêté\n"); code = -1; } if (ferror(stdin)) { perror("L'erreur suivante s'est produite"); code = -1; } if (code != 1) { return EXIT_FAILURE; } else { printf("La saisie est apparemment correcte, " "vous avez entré : %d\n", nombre1); } while ((c = getchar()) != '\n' && c != EOF) /* purge de stdin pour le prochain scanf */; /* ici scanf suivant, etc. */ return 0; }
pour éviter ceci :
Les valeurs acceptables pour un short int sont de -32768 à 32767
saisir nombre1:
99999
La saisie est apparemment correcte, vous avez entré : -31073
comment sait-on si l'utilisateur n'a pas réellement tapé -31073 ? y a-t-il un autre contrôle d'erreur possible qui m'échappe (limiter la saisie en caractères ici n'aide pas vraiment) ?
ce sont ces difficultés qui me font préférer fgets et strtol pour valider une saisie numérique.
Dal
@sambia : si l'utilisateur tape "toto", tu es bien avancé avec ton code ;-)
Sur les autres questions, en testant la valeur de retour de sscanf on tombe sur les mêmes problèmes que scanf, les fonctions étant de la même famille, c'est à dire un contrôle d'erreur difficile.
@fiddy : y a-t-il quelque chose à faire avec scanf qui m'échappe ?
Dal
Sur les autres questions, en testant la valeur de retour de sscanf on tombe sur les mêmes problèmes que scanf, les fonctions étant de la même famille, c'est à dire un contrôle d'erreur difficile.
@fiddy : y a-t-il quelque chose à faire avec scanf qui m'échappe ?
Dal
Bonjour, je ne suis pas du tout d'accord avec toi sur certains point, et le choix de sscanf à son importance contrairement à une utilisation simple de scanf (comme le cas dans les derniers posts). Dans le cas de mon code, il fait une conversion de la chaine ou du caractère en un entier, si la chaine saisie ou le caractère tapé n'est un chiffre, alors de fait, la conversion ne pourra pas ce faire et renverra 0 grace à la valeur initialisée avec notre variable locale, et en plus cela nous permet indirectement de contrôler la saisie et laisser le temps à l'utilisateur de comprendre pourquoi le résultat de l'addition est incorrect (parce qu'il a saisi un caractère).
Et pour info scanf ou sscanf renvoient le nombre d'éléments d'entrée correctement mis en correspondance, ce nombre peut-être plus petit que le nombre d'éléments attendus, et même être nul, s'il y a une erreur de mise en correspondance.
Et l'on remarquera que je n'ai pas utilisé scanf mais bien fgets dans ma fonction puis sscanf pour transtyper et ainsi contrôler la saisie, et je me préoccupe pas du retour d'erreur de sscanf car s'il n'a pas transtypé il renverra 0 la valeur de ma variable.
Et pour info scanf ou sscanf renvoient le nombre d'éléments d'entrée correctement mis en correspondance, ce nombre peut-être plus petit que le nombre d'éléments attendus, et même être nul, s'il y a une erreur de mise en correspondance.
Et l'on remarquera que je n'ai pas utilisé scanf mais bien fgets dans ma fonction puis sscanf pour transtyper et ainsi contrôler la saisie, et je me préoccupe pas du retour d'erreur de sscanf car s'il n'a pas transtypé il renverra 0 la valeur de ma variable.
Bonjour,
@[Dal],
Il n'y a hélas pas de moyen standard de contrôler finement une saisie numérique avec scanf() comme tu le souhaites. La norme ne requiert pas le placement de ERANGE dans errno en cas de nombre en dehors des bornes (contrairement à strtol()).
Il faut donc lire la chaîne au format texte et utiliser strtol() pour conversion.
Mais même, l'utilisation de fgets() (ou scanf() en faisant attention)/strtol()des deux n'est pas si simple. Il y a pas mal de piège. D'où l'intérêt de se faire une bonne fois pour toute une fonction de lecture sécurisée pour la réutiliser comme tu l'as indiqué ;-).
Cdlt,
@[Dal],
Il n'y a hélas pas de moyen standard de contrôler finement une saisie numérique avec scanf() comme tu le souhaites. La norme ne requiert pas le placement de ERANGE dans errno en cas de nombre en dehors des bornes (contrairement à strtol()).
Il faut donc lire la chaîne au format texte et utiliser strtol() pour conversion.
Mais même, l'utilisation de fgets() (ou scanf() en faisant attention)/strtol()des deux n'est pas si simple. Il y a pas mal de piège. D'où l'intérêt de se faire une bonne fois pour toute une fonction de lecture sécurisée pour la réutiliser comme tu l'as indiqué ;-).
Cdlt,
Sous Linux, en revanche, le code suivant marche bien en passant à gcc l'option -std=c99 :
Cela dit, scanf ne te permettra qu'un très faible contrôle d'erreur. C'est mieux de faire autrement pour lire un nombre de façon robuste.
Lis ceci à ce sujet pour comprendre pourquoi.
Dal
Le lien de la première réponse va beaucoup m'aider je pense car en fait je pense ne pas avoir compris ce que signifie char. Pour moi mettre char devant une variable signifie OBLIGATOIREMENT et UNIQUEMENT que cette variable est un entier compris entre -127 et +128.
Donc mettre %c+%c je voyais cela comme la "simple addition " de deux nombres entiers. Or cela peut être le cas (Cf votre exemple) mais ce n'est pas SYSTEMATIQUEMENT le cas.
Pouvez vous juste me préciser à quoi corresponde dans le tableau qui s'appelle specifiers les termes de la ligne suivante:
length d i u o x f e g a c s [] [^] p n
Je suis qu'au début de la leçon (une dizaine de page) sur C mais je me rends compte qu'on pourrait déjà écrire un livre sur ces quelques pages :))
Le standard définit comme étant un type entier, devant être suffisamment grand pour stocker tous les éléments du codage de caractères utilisé par défaut à l'exécution. La valeur entière représentant un caractère est alors garantie comme étant positive.
La taille d'un peut varier selon l'implémentation (le compilateur et l'environnement pour lequel le compilateur est sensé produire des exécutables).
le standard définit des valeurs minimales pour les limites d'un , qui sont effectivement -127 et +127 (pas 128).
Cependant, chaque implémentation peut définir des limites supérieures.
Les valeurs effectivement pertinentes pour ton compilateur sont définies dans qui doit contenir un et un .
2.
Il faut aussi comprendre la différence entre le caractère et sa valeur numérique (son code ASCII dans le codage de caractères ASCII).
voilà une illustration de ce que je te dis ci-avant :
chez moi ce code produit :
3.
Le tableau auquel tu fais référence sur la page http://www.cplusplus.com/reference/cstdio/scanf/ et qui contient une colonne dénommée "length" est le 3ème tableau présent sur cette page, qui est un tableau explicatif des sous-spécificateurs ("length sub-specifier") de taille utilisables avec les spécificateurs de type mentionnés dans le 1er tableau.
Les différentes colonnes " " visent ces spécificateurs de type utilisés par scanf, et le tableau permet de déterminer les types C correspondants effectivement attendus lorsque tu les combines avec des sous-spécificateurs de taille tels que , , , , etc. (qui sont les lignes du tableau)
est une des instructions les plus complexes du C.
Dal
Encore merci de la qualité de tes explications.
Gouager