J'essaie d'apprendre le C et je crée un programme très simple qui demandera votre nom puis l'affichera.
#include<stdio.h> main() { char name[30]; printf("\n\tWhat is your name?:"); scanf("%c",&name); printf("\n\tHi,%c.n\n",name); }
Après l'avoir compilé et essayé de taper un nom il donne juste une lettre aléatoire comme sortie de printf
.
4 Réponses :
Here
int main(void) /* No argument i.e void */ { char name[30] = {}; /* initialize the char buffer */ printf("\n\tWhat is your name?:"); scanf("%s",name); printf("\n\tHi,%s\n",name); return 0; /* Add this */ }
nom
est un tampon de caractères de 30
caractères, c'est-à-dire que vous pouvez stocker un maximum de 29
caractères comme nom d'utilisateur et 1
octet, vous devez réserver pour les caractères \ 0
.
Et ici
int main(int argc, char *argv[]) { /*...*/ }
puisque name
est un tableau de caractères et pour scanner le tampon de caractères au moment de l'exécution, utilisez le spécificateur de format % s
. Par exemple,
int main(void) { /*...*/ }
Et lors de l'impression de nom
, utilisez % s
au lieu de % c
. Par exemple,
gcc -Wall -Wextra -pedantic -Werror test.c
Note latérale, compilez toujours avec des indicateurs d'avertissement minimaux comme -Wall
. Par exemple
printf("\n\tHi,%s.n\n",name);
De plus, votre version de main ()
n'est pas correcte comme le dit la norme
5.1.2.2.1 Démarrage du programme Il doit être défini avec un type de retour de int et sans paramètre :
scanf("%s", name);ou avec deux paramètres (appelés ici argc et argv, bien que les noms peuvent être utilisés, car ils sont locaux à la fonction dans laquelle ils sont déclaré):
scanf("%c",&name); /* %c is for scanning single character */
Par exemple
char name[30];
Remplacez ceci:
prog.c:2:1: warning: return type defaults to 'int' [-Wimplicit-int] 2 | main() | ^~~~ prog.c: In function 'main': prog.c:6:9: warning: format '%c' expects argument of type 'char *', but argument 2 has type 'char (*)[30]' [-Wformat=] 6 | scanf("%c",&name); | ~^ ~~~~~ | | | | | char (*)[30] | char * prog.c:7:17: warning: format '%c' expects argument of type 'int', but argument 2 has type 'char *' [-Wformat=] 7 | printf("\n\tHi,%c.n\n",name); | ~^ ~~~~ | | | | int char * | %s
par ceci:
printf("\n\tHi,%s.n\n", name);
puisque nom
est un tableau de caractères, en d'autres termes une chaîne, pour laquelle nous utilisons le spécificateur de format % s
. C'est pourquoi nous passons le tableau entier comme 2ème paramètre de la méthode, donc nous n'utilisons plus &
.
Le % c
est utilisé lorsque nous voulons utiliser exactement un caractère.
De même, vous devez également imprimer avec le spécificateur de format de chaîne, comme ceci:
scanf("%s", name);
où je fais je ne sais pas si vous souhaitez que le ".n" soit contenu dans la sortie, mais il semble que vous savez déjà comment utiliser un caractère de nouvelle ligne ...
Vous pouvez facilement comprendre cela en activant les indicateurs d'avertissement dans votre compilateur. Dans GCC par exemple, j'ai compilé comme ceci:
gcc prog.c -Wall -Wextra
et obtenu:
scanf("%c", &name);
où le premier avertissement peut disparaître en déclarant la méthode main comme int main (void)
, et les deuxième et troisième comme nous l'avons vu précédemment (en utilisant le % s
).
p>
Il y a quelques problèmes avec votre code. Regardons:
int main(void) { char name[30]; printf("\n\tWhat is your name?:"); scanf("%s",name); printf("\n\tHi,%s\n",name); }
Vous devriez vraiment déclarer le type de retour pour main
, qui est traditionnellement int
.
printf("\n\tHi,%c.n\n",name);
Pas de vrai problème ici, sauf que vous vous préparez pour un dépassement de tampon classique. Si quelqu'un tape plus de 30 caractères dans votre programme, votre programme écrira des données à des endroits où il ne devrait pas. C'est une erreur de sécurité classique. Ce n'est pas grand-chose ici dans cette application jouet, mais il est important de connaître
scanf("%c",&name);
Vous utilisez % c
ici comme spécificateur de format. Cela a probablement du sens puisque le type de données ressemble à char
, mais en fait c'est char []
, c'est-à-dire un tableau de caractères. Utilisez plutôt $ s
pour collecter une chaîne entière. De plus, vous n'avez vraiment pas besoin du &
avant que name
... name
contienne l'adresse de départ du tableau, et & name
signifie la même chose.
char name[30]; printf("\n\tWhat is your name?:");
Même problème ici: utilisez à nouveau % s
.
Voici une version qui fonctionne:
main() {
Utilisation du compilateur clang
, obtention des messages d'avertissement suivants:
#include <stdio.h> #include <string.h> #define NAME_LEN 30 int main(void) { char name[NAME_LEN]; printf("\n\tWhat is your name? : "); if (fgets(name, NAME_LEN, stdin) == NULL) { fprintf (stderr, "Input error"); return -1; } name[strcspn(name, "\n")] = 0; // to remove trailing \n from input buffer printf("\n\tHi, %s\n",name); return 0; }
Le premier avertissement concerne l'absence de spécificateur de type main ()
. Dans l'ancienne version de C (C89 / 90), si le spécificateur de type est manquant, il sera défini par défaut sur int
. Bien sûr, vous recevrez un message d'avertissement lors de la compilation avec le compilateur C99 & C11
car cette déclaration implicite n'est plus prise en charge.
Le deuxième message d'avertissement concerne l'argument incompatible pour % c
spécificateur de format. Si vous souhaitez saisir une chaîne, vous devez utiliser le spécificateur de format % s
. Mais rappelez-vous que le spécificateur de format % s
correspond à une séquence de caractères non blancs. Si un spécificateur de largeur est utilisé, correspond à la largeur ou jusqu'au premier caractère d'espacement, selon celui qui apparaît en premier. Donc, si vous donnez une entrée comme
if (fgets(name, NAME_LEN, stdin) == NULL) { fprintf (stderr, "Input error"); return -1; } name[strcspn(name, "\n")] = 0; // to remove trailing \n from input buffer
, il ne consommera que nom
car il y a un espace après le mot nom
dans l'entrée. Le reste de l'entrée restera dans le tampon d'entrée.
Au lieu d'utiliser scanf ()
, vous devriez utiliser fgets ()
, comme ceci:
name surname
En savoir plus sur fgets ()
ici .
Le troisième avertissement concerne l'utilisation d'un spécificateur de format incompatible et de son argument correspondant dans printf ()
. Si vous voulez imprimer une chaîne, vous devez utiliser le spécificateur de format % s
.
En les mettant ensemble, vous pouvez faire:
prg.c:2:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int] main() ^ prg.c:6:12: warning: format specifies type 'char *' but the argument has type 'char (*)[30]' [-Wformat] scanf("%c",&name); ~~ ^~~~~ prg.c:7:24: warning: format specifies type 'int' but the argument has type 'char *' [-Wformat] printf("\n\tHi,%c.n\n",name); ~~ ^~~~ %s
"% c"
est le spécificateur de format pour un caractère. Utilisez"% s"
.Recevez-vous des messages d'avertissement lors de la compilation de votre code? Ils sont là pour une raison quelconque ... ne les ignorez pas.
Cela a fonctionné grâce. Je pensais que "% s" était pour "string", donc je ne l'ai pas essayé. Cependant, il ne donnait aucun avertissement lors de la compilation.
Si vous n'avez reçu aucun avertissement de votre compilateur, vous devez savoir comment le faire vous donner des avertissements utiles (nécessaires) - ou obtenir un meilleur compilateur. Par exemple, en utilisant GCC (GNU C Compiler de la GNU Compiler Collection), vous devez compiler avec
gcc -Wall -Wextra -Werror -std = c11 -O3 -g…
ou à peu près, et à cause de < code> -Werror , vous ne pourrez pas exécuter le code tant qu'il ne sera pas compilé sans avertissement.Oui, "% s" est pour une chaîne, c'est-à-dire une séquence de caractères. Voilà ce qu'est un nom.
Merci à tous pour leurs réponses, ils m'apprennent tous une chose différente.