Int et char sont dans un bateau

Résolu/Fermé
Gouager - Modifié par pijaku le 5/02/2014 à 12:37
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 - 6 févr. 2014 à 22:46
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?!
#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:

4 réponses

[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
Modifié par [Dal] le 4/02/2014 à 20:03
Salut,

Ton problème vient du fait que tu ne peux pas spécifier
%c
car ce n'est pas un caractère que tu veux, mais un nombre décimal, et que si tu spécifies
%d
sans 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;
}


%d
doit être utilisé, car ce que tu attends, c'est bien un nombre décimal, et pas un caractère

le spécificateur de taille
h
permet d'indiquer à scanf qu'il doit accueillir un
short int
.

si tu tiens vraiment à utiliser des
char
(des
signed char
selon ce que tu dis), il te faudra utiliser du C99 et le spécificateur
hh
, qui te permet de gérer des
signed char
avec
%d
.

http://www.cplusplus.com/reference/cstdio/scanf/


Dal
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
5 févr. 2014 à 12:07
Si tu es sous Windows, et que tu utilises MinGW, bien que les versions actuelles de gcc supportent le spécificateur
hh
pour scanf, MinGW utilise la core runtime library de Microsoft msvcrt.dll qui, elle, ne semble pas le supporter. Du moins, c'est le cas sur mon système et je ne semble pas être le seul.

Sous Linux, en revanche, le code suivant marche bien en passant à gcc l'option -std=c99 :

#include <stdio.h>

int main(void)
{
    char nombre = 0;
    char nombre1 = 0;
    char nombre2 = 0;
    printf("saisir nombre1:\n");
    scanf("%hhd", &nombre1);
    printf("saisir nombre2:\n");
    scanf("%hhd", &nombre2);
    nombre = nombre1 + nombre2;
    printf("%d+%d=%d\n", nombre1, nombre2, nombre);
    return 0;
}


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
0
Merci beaucoup pour ces explications. La deuxième étant trop compliqué pour moi mais je vais lire avec attention le lien.
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 :))
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
Modifié par [Dal] le 5/02/2014 à 15:05
1.

Le standard définit
char
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
char
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
signed char
, 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
<limits.h>
qui doit contenir un
#define SCHAR_MIN
et un
#define SCHAR_MAX
.

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 :

#include <stdio.h>
#include <limits.h>

int main(void)
{
    char c = 'a';
    printf("c contient un caractère : %c\n", c);
    printf("sa valeur décimale est : %d\n", c);
    printf("il peut contenir des valeurs entières allant de %d à %d\n",
            SCHAR_MIN, SCHAR_MAX);
    return 0;
}


chez moi ce code produit :

c contient un caractère : a
sa valeur décimale est : 97
il peut contenir des valeurs entières allant de -128 à 127

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 "
d i u o x f e g a c s [] [^] p n
" 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
h
,
hh
,
l
,
ll
, etc. (qui sont les lignes du tableau)

scanf
est une des instructions les plus complexes du C.


Dal
0
Merci d'avoir pris le temps de m'expliquer tout cela. Je n'ai pas tout compris mais j'ai progressé. "Le boeuf est lent mais la terre est patiente"
0
Je précise, par rapport à la dernière réponse que tu m'as apportée, que ton point 2. m'a permis de comprendre la signification de char tout comme les liens (que je suis en train de lire et qui sont extrêmement bien faits).
Encore merci de la qualité de tes explications.

Gouager
0
sambia39 Messages postés 610 Date d'inscription vendredi 31 juillet 2009 Statut Membre Dernière intervention 9 février 2023 49
5 févr. 2014 à 22:30
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.
0
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.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 842
6 févr. 2014 à 07:13
Limite de scanf ? Il n'y en a pas. Complexité ? Là oui.
Parmi les trucs les plus dangereux si on utilise mal scanf, la chaine de caractère trop grande => plantage ou modification de variables dans le code... Écriture d'un caractère au lieu d'un nombre => boucle infinie. Et j'en passe :-)
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
6 févr. 2014 à 11:27
@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 :

#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
0
sambia39 Messages postés 610 Date d'inscription vendredi 31 juillet 2009 Statut Membre Dernière intervention 9 février 2023 49
6 févr. 2014 à 15:19
Bonjour, ou faire comme ceci
#include <stdio.h>

const int fFormatSaisie(void){
	int iVal=0;
	char pChar[10]={'\0'};
	fgets(pChar,sizeof(pChar),stdin); 
	sscanf(pChar, "%d", &iVal);
	return iVal;
}
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
6 févr. 2014 à 15:47
@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
0
sambia39 Messages postés 610 Date d'inscription vendredi 31 juillet 2009 Statut Membre Dernière intervention 9 février 2023 49
6 févr. 2014 à 17:37
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.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 842
6 févr. 2014 à 21:26
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,
0
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 1 092
6 févr. 2014 à 22:46
ok, j'espérais que tu aies dans ton escarcelle une astuce avec scanf de derrière les fagots dont tu as le secret :-D

merci de ton feedback fiddy


Dal
0