163 votes

Lire une chaîne de caractères avec scanf

Je suis un peu confus à propos de quelque chose. J'avais l'impression que la manière correcte de lire une chaîne de caractères C avec scanf() est allé dans le sens de

(ne tenez pas compte du possible dépassement de tampon, c'est juste un exemple simple)

char string[256];
scanf( "%s" , string );

Cependant, la méthode suivante semble également fonctionner,

scanf( "%s" , &string );

Est-ce que c'est juste mon compilateur (gcc), de la chance, ou autre chose ?

0 votes

Dans le second cas, il n'y a pas de dépassement de tampon possible, puisque vous n'utilisez pas du tout ce tampon. Ou alors, on peut dire que toute chaîne de plus de 3 caractères fera déborder votre "tampon".

0 votes

Je faisais référence au premier exemple. De plus, d'autres ont déjà souligné ce qui se passe ici.

0 votes

Yup. Je l'ai essayé, et Gareth a raison. Bizarre.

152voto

Gareth McCaughan Points 12261

Un tableau se "décompose" en un pointeur vers son premier élément, donc scanf("%s", string) est équivalent à scanf("%s", &string[0]) . D'autre part, scanf("%s", &string) passe un pointeur vers char[256] mais il pointe vers le même endroit.

Puis scanf lorsqu'il traite la fin de sa liste d'arguments, il essaiera d'extraire un fichier de type char * . C'est la bonne chose à faire quand vous avez passé en string ou &string[0] mais quand vous avez passé en &string vous dépendez de quelque chose que la norme du langage ne garantit pas, à savoir que les pointeurs &string et &string[0] -- les pointeurs vers des objets de types et de tailles différents qui commencent au même endroit -- sont représentés de la même manière.

Je ne crois pas avoir jamais rencontré un système sur lequel cela ne fonctionne pas, et dans la pratique, vous êtes probablement en sécurité. Néanmoins, c'est une erreur, et cela pourrait échouer sur certaines plateformes. (Exemple hypothétique : une implémentation de "débogage" qui inclut des informations de type avec chaque pointeur. I pensez à l'implémentation C sur les "Lisp Machines" de Symbolics faisait quelque chose comme ça).

2voto

T.E.D. Points 26829

Wow. C'était une nit que je ne connaissais pas. Je change ma réponse après l'avoir essayé.

Il semble que cela fonctionne, en quelque sorte. Cependant, votre compilateur aurait probablement dû vous donner un avertissement. Mon gcc l'a fait.

Il semble que les fonctions et les tableaux donnent tous deux le même résultat pour name et &name lorsqu'il est utilisé dans le contexte d'un pointeur.

-2voto

Dadam Points 1164

string est un tableau. Disons que le début du tableau est à l'adresse 1024. Lorsque vous l'utilisez, il est transformé en un pointeur. Un pointeur est une variable contenant une adresse - dans notre cas 1024. C'est scanf("%s", string) .

Lorsque vous tapez &string la chaîne elle-même n'est pas transformée en pointeur. Au lieu de cela, son adresse est prise et utilisée comme valeur de cette expression. Et l'adresse est 1024. Et comme scanf() ne peut pas reconnaître le type de pointeur passé, tout se passe bien.

Essayez

char \*string = "                 "; //dirty, but works
scanf("%s", string);
scanf("%s", &string); //this will crash

Pourquoi se plante-t-il ? Cette chaîne n'est pas un tableau, c'est un pointeur. Lorsque vous utilisez string la valeur de celui-ci est utilisée - disons 1024 encore. Mais lorsque vous utilisez &string l'adresse du pointeur (par exemple 1020), et non sa valeur, est utilisée.

-13voto

angelita Points 1

Je pense que le texte ci-dessous est exact et qu'il peut vous aider. N'hésitez pas à le corriger si vous trouvez des erreurs. Je suis nouveau en C.

char str[]  
  1. tableau de valeurs de type char, avec sa propre adresse en mémoire
  2. tableau de valeurs de type char, avec sa propre adresse en mémoire autant d'adresses consécutives que d'éléments dans le tableau
  3. y compris le caractère nul de la terminaison '\0' &str , &str[0] et str tous les trois représentent le même emplacement dans la mémoire qui est l'adresse du premier élément du tableau. str

    char *strPtr = &str[0] ; //déclaration et initialisation

Vous pouvez aussi le diviser en deux :

char *strPtr; strPtr = &str[0];
  1. strPtr est un pointeur vers un char
  2. strPtr points du tableau str
  3. strPtr est une variable avec sa propre adresse en mémoire
  4. strPtr est une variable qui stocke la valeur de l'adresse &str[0]
  5. strPtr sa propre adresse en mémoire est différente de l'adresse en mémoire qu'il stocke (adresse du tableau en mémoire alias &str[0])
  6. &strPtr représente l'adresse de strPtr lui-même

Je pense que vous pourriez déclarer un pointeur sur un pointeur comme :

char **vPtr = &strPtr;  

déclare et initialise avec l'adresse du pointeur strPtr

Vous pouvez aussi vous diviser en deux :

char **vPtr;
*vPtr = &strPtr
  1. *vPtr pointe sur le pointeur strPtr
  2. *vPtr est une variable avec sa propre adresse en mémoire
  3. *vPtr est une variable qui stocke la valeur de l'adresse &strPtr
  4. commentaire final : vous ne pouvez pas faire str++ , str L'adresse est un const mais vous pouvez faire strPtr++

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X