/*d'apr=C3=A8s K&R 2 : "there is one difference between an array name and a
pointer that must be kept in mind. A pointer is a variable , so pa =3D a
and pa++ are legal. But an array name is not a variable. constructions
like a=3Dpa and a++ are illegal. Je veux juste avoir une id=C3=A9e des
messages d'erreur relatifs aux pointeurs pour l'instant au niveau des
chaines de caract=C3=A8res. */
printf("\n%s", Chaine) ; /* A : OK */
printf("\n%s", *Chaine) ; /* B : warning: format =E2=80=98%s=E2=80=99 exp=
ects type
=E2=80=98char *=E2=80=99, but argument 2 has type =E2=80=98int=E2=80=99 .=
.. Segmentation fault :
*/
printf("\n%s", *(Chaine+0) ) ; /* C : warning: format =E2=80=98%s=E2=80=99=
expects
type =E2=80=98char *=E2=80=99, but argument 2 has type =E2=80=98int=E2=80=
=99 ... Segmentation
fault : */
printf("\n%c", *(Chaine+0) ) ; /* D: OK */
printf("\n%s", Chaine+0 ) ; /* E : OK */
printf("\n%s", Chaine+1 ) ; /* F : OK */
printf("\n%s", &Chaine ) ; /* G : warning: format =E2=80=98%s=E2=80=99 exp=
ects type
=E2=80=98char *=E2=80=99, but argument 2 has type =E2=80=98char (*)[10]=E2=
=80=99 ... OK */
printf("\n%s", &Chaine[0] ) ; /* H: OK */
/*CHAINE 2 */
printf("\n%s", &Chaine2) ; /* I : warning: format =E2=80=98%s=E2=80=99 exp=
ects type
=E2=80=98char *=E2=80=99, but argument 2 has type =E2=80=98char * (*)[2] ..=
. r=C3=A9sultat
ind=C3=A9termin=C3=A9*/
printf("\n%o", &Chaine2) ; /* J : warning: format =E2=80=98%o=E2=80=99 exp=
ects type
=E2=80=98unsigned int=E2=80=99, but argument 2 has type =E2=80=98char * (*)=
[2] ... r=C3=A9sultat :
27776137614 */
printf("\n%c", *Chaine2[1]) ; /* K : warning: format =E2=80=98%c=E2=80=99=
expects
type =E2=80=98int=E2=80=99, but argument 2 has type =E2=80=98char **=E2=80=
=99... r=C3=A9sultat : vide */
printf("\n%s", Chaine2[0]) ; /* L : OK */
printf("\n%s", Chaine2) ; /* M : warning: format =E2=80=98%s=E2=80=99 expe=
cts type
=E2=80=98char *=E2=80=99, but argument 2 has type =E2=80=98char **=E2=80=99=
...resultat : =EF=BF=BD=EF=BF=BD=EF=BF=BD=EF=BF=BDE#abc */
printf("\n\n") ;
return 0 ;
}
/*
A :
Resultat : abc
Je comprends ici que Chaine est un tableau (ou une chaine constante
pour =C3=AAtre plus pr=C3=A9cis?).
Le paragraphe suivant l'extrait du K&R pr=C3=A9c=C3=A9dent dis que lorsqu'u=
n nom
de tableau est envoy=C3=A9 =C3=A0 une fonction, c'est l'emplacement du
1er =C3=A9l=C3=A9ment qui est envoy=C3=A9... et =C3=A0 l'int=C3=A9rieur de =
cette fonction, cet
argument est une variable locale
Je ne comprends pas que pour printf avec %s, * ou le contenu de Chaine
ne soit pas appel=C3=A9 mais ce qui me semble =C3=AAtre l'adresse en m=C3=
=A9moire de
Chaine comme lorsqu'on passe char *pointeur ; pointeur =3D Chaine ou
pointeur =3D &Chaine[0]. Le point H va dans ce sens
Ce premier cas est celui qui me fait toujours r=C3=A9fl=C3=A9chir et peut m=
e
donner une erreur . Surtout que dans ce cas scanf ajoute de l'insulte
=C3=A0 la blessure car : scanf("%s", Chaine) au lieu de scanf("%s",
&Chaine) comme on peut s'y attendre ;
char Chaine[10] ;
printf("\nEntrez une chaine : ") ;
scanf("%s", &Chaine[0]) OK MAIS scanf("%s", &Chaine) affiche
warning: format =E2=80=98%s=E2=80=99 expects type =E2=80=98char *=E2=80=99,=
but argument 2 has type
=E2=80=98char (*)[10]=E2=80=99 mais la saisie se fait quand m=C3=AAme
B :
Resultat : Segmentation fault
Le warning dit que le 2=C3=A8me argument est de type int.
Ce n'est pas la premi=C3=A8re fois que j'ai ce message. Est-ce que je dois
comprendre que dans printf, %s est le 1er argument, et *Chaine est le
second? Alors comme le pointeur *Chaine n'a pas =C3=A9t=C3=A9 d=C3=A9clar=
=C3=A9, *Chaine
est de type int par d=C3=A9faut ?
Ensuite, le K et R dis pour pa =3D a ...un tableau constant a[i] peut
aussi s'=C3=A9crire *(a+i) pourquoi pas *a (soit le contenu de a) avec %s
affiche une chaine?
C :
Resultat : Segmentation fault
Resultat identique si *(Chaine+1), *(Chaine+2), *(Chaine+3) etc...
*(Chaine+9)
L'argument %s semble ici bloquer le d=C3=A9roulement du programme. Ca
para=C3=AEt coh=C3=A9rent avec %c dans printf :
D :
Resultat : a
E:
Resultat : abc
F:
Resultat : bc
G :
Resultat : abc
1ere fois que je vois ce warning, je dois avouer que je n'avais pas
penser =C3=A0 appeler un tableau d'une chaine constante ou d'entier avec
l'adresse &. Le '&' est =C3=A0 mes yeux associ=C3=A9 aux pointeurs. A ma gr=
ande
surprise, le code fonctionne. En tant que d=C3=A9butant avec le langage C,
je trouve int=C3=A9ressant le warning: il montre bien qu'un tableau est un
pointeur vers le type de donn=C3=A9es dans lequel il a =C3=A9t=C3=A9 d=C3=
=A9finit/d=C3=A9clar=C3=A9
ici : char (*)[10], c=C3=A0d 10 pointeurs vers des donn=C3=A9es de type
caract=C3=A8res?
H:
Resultat : abc
I :
Resultat : des carr=C3=A9s s'affichent : =10=EF=BF=BD`=EF=BF=BD=04 et abc
Je suppose que c'est la repr=C3=A9sentation d'emplacements m=C3=A9moire (vo=
ir I)
J:
Resultat : 27776137614
Le message confirme que ce sont bien 2 pointeurs sur char
Je suppose que c'est l'adresse de *Chaine2 repr=C3=A9sent=C3=A9e sous la fo=
rme
d'un entier?
K :
Resultat : abc
Je ne comprends pas l'erreur "invalid initializer". Pourtant le code
fonctionne m=C3=AAme avec : *Chaine[0], *Chaine[20]...
L :
Resultat : abc
error: invalid initializer
error: expected expression before =E2=80=98]=E2=80=99 token
error: array subscript is not an integer
warning: format =E2=80=98%c=E2=80=99 expects type =E2=80=98int=E2=80=99, bu=
t argument 2 has type =E2=80=98char
*=E2=80=99
Et pourtant =C3=A7a fonctionne.
Invalid initializer est dans J alors je suppose que la r=C3=A9ponse
pr=C3=A9c=C3=A9dente satisfait la question pr=C3=A9sente.
expected expression ... : je comprends que je dois mettre un indice
entre [ ] . Dans J, les indices ne me semblent pas utiles et ici, ils
seraient utiles?
array subscript is not an integer : je ne comprends pas
warning : format %c expects type int ... : selon moi, %c attend un
caract=C3=A8re et non pas un int ...
M:
Resultat in=C3=A9dit : =EF=BF=BD=EF=BF=BD=EF=BF=BD=EF=BF=BDE#abc
warning: format =E2=80=98%s=E2=80=99 expects type =E2=80=98char *=E2=80=99,=
but argument 2 has type
=E2=80=98char **=E2=80=99
Je ne suis pas s=C3=BBre de comprendre.
-o-
Je vais arr=C3=AAter l=C3=A0 =C3=A9tant arriv=C3=A9 =C3=A0 la moiti=C3=A9 d=
e l'alphabet et les
besoins physiologiques se font pressant...surtout que le tableau
multidimensionnel chaine2 permet encore d'autres combinaisons...
D'autre part, il n'y a pas de type 'Char' en C standard. C'est 'char'.
printf("n%s", Chaine) ; /* A : OK */
Le 'n' indique la fin de ligne, il se place donc ... en fin de ligne !
printf ("%sn", Chaine); /* A : OK */
en effet, il force l'émission des caractères. Sinon, le caractères placés après risquent de ne pas être émis ...
printf("n%s", *Chaine) ; /* B : warning: format %s expects type char *, but argument 2 has type int ... Segmentation fault : */
Ben oui, normal. *Chaine ou *(Chaine + 0) ou encore Chaine[0], désigne un caractère (type char), qui est automatiquement converti en int. Cet int n'a quasiment aucune chance d'être une adresse valide ("%s" attends l'adresse d'une chaine de caractères). Tu veux peut être "%c" pour voir le caractère ?
printf("n%s", *(Chaine+0) ) ; /* C : warning: format %s expects type char *, but argument 2 has type int ... Segmentation fault : */
Même problème
printf("n%c", *(Chaine+0) ) ; /* D: OK */ printf("n%s", Chaine+0 ) ; /* E : OK */ printf("n%s", Chaine+1 ) ; /* F : OK */
printf("n%s", &Chaine ) ; /* G : warning: format %s expects type char *, but argument 2 has type char (*)[10] ... OK */
Non, pas OK. Le comportement est indéfini. On ne fait pas ça.
printf("n%s", &Chaine[0] ) ; /* H: OK */
/*CHAINE 2 */
printf("n%s", &Chaine2) ; /* I : warning: format %s expects type char *, but argument 2 has type char * (*)[2] ... résultat indéterminé*/
Oui, carrément n'importe quoi ...
printf("n%o", &Chaine2) ; /* J : warning: format %o expects type unsigned int, but argument 2 has type char * (*)[2] ... résult at : 27776137614 */
Pareil. Tu programmes au hasard ? Tu testes le compilateur ? Pourquoi "%o" ? Tu trouves que l'octal est adapté ?
printf("n%c", *Chaine2[1]) ; /* K : warning: format %c expects type int, but argument 2 has type char **... résultat : vid e */
Oui, portnawak ...
printf("n%s", Chaine2[0]) ; /* L : OK */
printf("n%s", Chaine2) ; /* M : warning: format %s expects type char *, but argument 2 has type char ** ...resultat : E#abc * /
Non, résultat indéfini, c'est tout ...
Il manque :
printf("%sn", Chaine2[1]) ; /* O : OK */
printf("nn") ;
Pas très utile si on prends soin de mettre le 'n' à la fin de l ligne, comme il se doit ...
return 0 ;
}
/* A : Resultat : abc
Je comprends ici que Chaine est un tableau (ou une chaine constante pour être plus précis?).
C'est un tableau de char initialisé modifiable. Sa valeur est {'a','b','c',0,0,0,0,0,0,0}
Le paragraphe suivant l'extrait du K&R précédent dis que lorsqu'un no m de tableau est envoyé à une fonction, c'est l'emplacement du 1er élément qui est envoyé...
Oui, c'est à dire une adresse. L'adresse du premier élément du tablea u si c'est le nom seul (<nom> ou <nom> + 0)
et à l'intérieur de cette fonction, cet argument est une variable locale
Oui, comme tous les arguments. Ici, c'est une variable locale de type 'adresse de char', dont un pointeur sur char (char *s, par exemple).
Je ne comprends pas que pour printf avec %s, * ou le contenu de
Chaine
ne soit pas appelé mais ce qui me semble être l'adresse en mémoire de Chaine comme lorsqu'on passe char *pointeur ; pointeur = Chaine ou pointeur = &Chaine[0]. Le point H va dans ce sens
Comme expliqué précédemment, "%s" attend l'adresse d'un tableau de char initialisé avec une chaine, donc terminée par un 0. Si on lui passe autre chose (*Chaine, par exemple), le comportement est indéfini.
Ce premier cas est celui qui me fait toujours réfléchir et peut me donner une erreur .
Y'a pas trop à réfléchir. Une fois qu'on sait ce qu'attend é%s", to ut est clair. Et c'est pareil avec scanf() (sauf que c'est la taille qui importe et non le contenu).
Surtout que dans ce cas scanf ajoute de l'insulte à la blessure car : scanf("%s", Chaine) au lieu de scanf("%s", &Chaine) comme on peut s'y attendre ;
Pourquoi & ? On a expliqué en long en large et travers que quand on passait le nom d'un tableau à une fonction, celui-ci était convertit en adresse du premier élément. On peut donc mettre :
scanf("%s", Chaine) ou scanf("%s", Chaine + 0) ou scanf("%s", &Chaine[0]) si on aime la complication.
Attention, cette saisie est dangereuse et pas paratique, car elle prend tout jusqu'au premier séparateur (espace, tab ou fin de ligne).
char Chaine[10] ; printf("nEntrez une chaine : ") ; scanf("%s", &Chaine[0]) OK MAIS scanf("%s", &Chaine) a ffiche warning: format %s expects type char *, but argument 2 has ty pe char (*)[10] mais la saisie se fait quand même
A tes risques et périls. Le comportement est indéterminé. On a déj à fort affaire avec les comportements normaux. Ne pas perdre de temps avec les comportements non définis ... Enfin, tu as voulu faire du C...
B : Resultat : Segmentation fault
Le warning dit que le 2ème argument est de type int. Ce n'est pas la première fois que j'ai ce message. Est-ce que je dois comprendre que dans printf, %s est le 1er argument, et *Chaine est le second?
Ben oui. C'est pas évident ?
Alors comme le pointeur *Chaine n'a pas été déclaré, *Chaine est de type int par défaut ?
Attention. Le rôle de * change selon le contexte.
Il sert
- soit d'opérateur de multiplication quand il est placé entre 2 opérandes : a * 2, a * b etc. - soit de déclarateur de pointeur dans une déclaration de variable : int *p; char const *s="hello" - soit d'opérateur de déréférencement quand il est appliqué à u n pointeur : inc c = *s, f (*s) etc.
ici, c'est le 3 ème cas. *Chaine est *(Chaine + 0), c'est à dire Chaine[0]. C'est donc un caractère qui n'a rien à voir avec une adresse. Le type est int, parce que l'appel de fonction avec un paramètre de type char est convertit en int.
Ensuite, le K et R dis pour pa = a ...un tableau constant a[i] peut aussi s'écrire *(a+i) pourquoi pas *a (soit le contenu de a) avec %s affiche une chaine?
Parce que dans ce cas, *a (valeur pointée par a) désigne un caractère et non une adresse ...
C : Resultat : Segmentation fault
Resultat identique si *(Chaine+1), *(Chaine+2), *(Chaine+3) etc... *(Chaine+9) L'argument %s semble ici bloquer le déroulement du programme. Ca paraît cohérent avec %c dans printf :
D : Resultat : a
E: Resultat : abc
F: Resultat : bc
G : Resultat : abc
Bah oui, normal. "%c" attend un int qui représente la valeur d'un caractère. Si on lui donne ce qu'il attend, tout va bien...
1ere fois que je vois ce warning, je dois avouer que je n'avais pas penser à appeler un tableau d'une chaine constante ou d'entier avec l'adresse &. Le '&' est à mes yeux associé aux pointeurs.
Peut importe. La réalité est que & est un opérateur qui retourne une valeur et un type. La valeur est l'adresse d'un objet. Le type retourné est 'pointeur sur le type de l'objet'. Appliqué à un tableau , ça retourne l'adresse du tableau (comme en C, le premier élément d'un tableau se trouve en [0], la valeur est la même qu'avec le nom du tableau), mais le type est différent. Ailiet de retourner le type 'pointeur sur un élément du tableau', on retourne 'pointeur sur le tableau' ce qui est très différent, et peut avoir des conséquences terribles si on utilise un offset : Chaine + 1 n'a pas du tout la même valeur que &Chaine+1.
A ma grande surprise, le code fonctionne.
Oui, la valeur est la même. "Ça tombe en marche" ... Mais c'est faux pour les raisons déjà expliquées.
En tant que débutant avec le langage C, je trouve intéressant le warning: il montre bien qu'un tableau est un pointeur vers le type de données dans lequel il a été définit/d éclaré ici : char (*)[10], càd 10 pointeurs vers des données de type caractères?
Oui, les warnings essayent d'aider à comprendre les subtilités du C... Mais pourquoi tu ne fais pas du Pascal ...
H: Resultat : abc
I : Resultat : des carrés s'affichent : ` et abc
Je suppose que c'est la représentation d'emplacements mémoire (voir I )
J: Resultat : 27776137614
Des comportements indéfinis ...
Le message confirme que ce sont bien 2 pointeurs sur char Je suppose que c'est l'adresse de *Chaine2 représentée sous la forme d'un entier?
Oui, en octal... Quelle idée. Le bon format pour une adresse est "%p" et il faut forcer le paramètre 'adresse' en (void *)
K : Resultat : abc
Je ne comprends pas l'erreur "invalid initializer". Pourtant le code fonctionne même avec : *Chaine[0], *Chaine[20]...
certainement pas. C'est printf("n%c", *(Chaine2[1])) . Attention à la préséance des opérateurs ...
L : Resultat : abc
error: invalid initializer error: expected expression before ] token error: array subscript is not an integer warning: format %c expects type int, but argument 2 has type char *
Et pourtant ça fonctionne. Invalid initializer est dans J alors je suppose que la réponse précédente satisfait la question présente. expected expression ... : je comprends que je dois mettre un indice entre [ ] . Dans J, les indices ne me semblent pas utiles et ici, ils seraient utiles? array subscript is not an integer : je ne comprends pas warning : format %c expects type int ... : selon moi, %c attend un caractère et non pas un int ...
Nan. "%c" attend un int représentant la valeur d'un caractère.
M: Resultat inédit : E#abc warning: format %s expects type char *, but argument 2 has ty pe char ** Je ne suis pas sûr de comprendre.
Il n'y a rien de prévu nativement pour représenter un tableau de pointeurs.
On 6 juin, 23:19, heron maladroit <cream10...@yahoo.com> wrote:
char Chaine[10] = "abc" ;
char *Chaine2[] = {"abc", "def" }; /* 2 pointeurs su r Char ... */
Les chaines étant par défaut, non modifiables en C, on préfère rest er
cohérent et portable comme ceci :
D'autre part, il n'y a pas de type 'Char' en C standard. C'est 'char'.
printf("n%s", Chaine) ; /* A : OK */
Le 'n' indique la fin de ligne, il se place donc ... en fin de
ligne !
printf ("%sn", Chaine); /* A : OK */
en effet, il force l'émission des caractères. Sinon, le caractères
placés après risquent de ne pas être émis ...
printf("n%s", *Chaine) ; /* B : warning: format %s expects type
char *, but argument 2 has type int ... Segmentation fault :
*/
Ben oui, normal. *Chaine ou *(Chaine + 0) ou encore Chaine[0], désigne
un caractère (type char), qui est automatiquement converti en int. Cet
int n'a quasiment aucune chance d'être une adresse valide ("%s"
attends l'adresse d'une chaine de caractères). Tu veux peut être "%c"
pour voir le caractère ?
printf("n%s", *(Chaine+0) ) ; /* C : warning: format %s expects
type char *, but argument 2 has type int ... Segmentation
fault : */
Même problème
printf("n%c", *(Chaine+0) ) ; /* D: OK */
printf("n%s", Chaine+0 ) ; /* E : OK */
printf("n%s", Chaine+1 ) ; /* F : OK */
printf("n%s", &Chaine ) ; /* G : warning: format %s expects type
char *, but argument 2 has type char (*)[10] ... OK */
Non, pas OK. Le comportement est indéfini. On ne fait pas ça.
printf("n%s", &Chaine[0] ) ; /* H: OK */
/*CHAINE 2 */
printf("n%s", &Chaine2) ; /* I : warning: format %s expects type
char *, but argument 2 has type char * (*)[2] ... résultat
indéterminé*/
Oui, carrément n'importe quoi ...
printf("n%o", &Chaine2) ; /* J : warning: format %o expects type
unsigned int, but argument 2 has type char * (*)[2] ... résult at :
27776137614 */
Pareil. Tu programmes au hasard ? Tu testes le compilateur ? Pourquoi
"%o" ? Tu trouves que l'octal est adapté ?
printf("n%c", *Chaine2[1]) ; /* K : warning: format %c expects
type int, but argument 2 has type char **... résultat : vid e */
Oui, portnawak ...
printf("n%s", Chaine2[0]) ; /* L : OK */
printf("n%s", Chaine2) ; /* M : warning: format %s expects type
char *, but argument 2 has type char ** ...resultat : E#abc * /
Non, résultat indéfini, c'est tout ...
Il manque :
printf("%sn", Chaine2[1]) ; /* O : OK */
printf("nn") ;
Pas très utile si on prends soin de mettre le 'n' à la fin de l
ligne, comme il se doit ...
return 0 ;
}
/*
A :
Resultat : abc
Je comprends ici que Chaine est un tableau (ou une chaine constante
pour être plus précis?).
C'est un tableau de char initialisé modifiable. Sa valeur est
{'a','b','c',0,0,0,0,0,0,0}
Le paragraphe suivant l'extrait du K&R précédent dis que lorsqu'un no m
de tableau est envoyé à une fonction, c'est l'emplacement du
1er élément qui est envoyé...
Oui, c'est à dire une adresse. L'adresse du premier élément du tablea u
si c'est le nom seul (<nom> ou <nom> + 0)
et à l'intérieur de cette fonction, cet
argument est une variable locale
Oui, comme tous les arguments. Ici, c'est une variable locale de type
'adresse de char', dont un pointeur sur char (char *s, par exemple).
Je ne comprends pas que pour printf avec %s, * ou le contenu de
Chaine
ne soit pas appelé mais ce qui me semble être l'adresse en mémoire de
Chaine comme lorsqu'on passe char *pointeur ; pointeur = Chaine ou
pointeur = &Chaine[0]. Le point H va dans ce sens
Comme expliqué précédemment, "%s" attend l'adresse d'un tableau de
char initialisé avec une chaine, donc terminée par un 0. Si on lui
passe autre chose (*Chaine, par exemple), le comportement est
indéfini.
Ce premier cas est celui qui me fait toujours réfléchir et peut me
donner une erreur .
Y'a pas trop à réfléchir. Une fois qu'on sait ce qu'attend é%s", to ut
est clair. Et c'est pareil avec scanf() (sauf que c'est la taille qui
importe et non le contenu).
Surtout que dans ce cas scanf ajoute de l'insulte
à la blessure car : scanf("%s", Chaine) au lieu de scanf("%s",
&Chaine) comme on peut s'y attendre ;
Pourquoi & ? On a expliqué en long en large et travers que quand on
passait le nom d'un tableau à une fonction, celui-ci était convertit
en adresse du premier élément. On peut donc mettre :
scanf("%s", Chaine)
ou
scanf("%s", Chaine + 0)
ou
scanf("%s", &Chaine[0])
si on aime la complication.
Attention, cette saisie est dangereuse et pas paratique, car elle
prend tout jusqu'au premier séparateur (espace, tab ou fin de ligne).
char Chaine[10] ;
printf("nEntrez une chaine : ") ;
scanf("%s", &Chaine[0]) OK MAIS scanf("%s", &Chaine) a ffiche
warning: format %s expects type char *, but argument 2 has ty pe
char (*)[10] mais la saisie se fait quand même
A tes risques et périls. Le comportement est indéterminé. On a déj à
fort affaire avec les comportements normaux. Ne pas perdre de temps
avec les comportements non définis ... Enfin, tu as voulu faire du
C...
B :
Resultat : Segmentation fault
Le warning dit que le 2ème argument est de type int.
Ce n'est pas la première fois que j'ai ce message. Est-ce que je dois
comprendre que dans printf, %s est le 1er argument, et *Chaine est le
second?
Ben oui. C'est pas évident ?
Alors comme le pointeur *Chaine n'a pas été déclaré, *Chaine
est de type int par défaut ?
Attention. Le rôle de * change selon le contexte.
Il sert
- soit d'opérateur de multiplication quand il est placé entre 2
opérandes : a * 2, a * b etc.
- soit de déclarateur de pointeur dans une déclaration de variable :
int *p; char const *s="hello"
- soit d'opérateur de déréférencement quand il est appliqué à u n
pointeur : inc c = *s, f (*s) etc.
ici, c'est le 3 ème cas. *Chaine est *(Chaine + 0), c'est à dire
Chaine[0]. C'est donc un caractère qui n'a rien à voir avec une
adresse. Le type est int, parce que l'appel de fonction avec un
paramètre de type char est convertit en int.
Ensuite, le K et R dis pour pa = a ...un tableau constant a[i] peut
aussi s'écrire *(a+i) pourquoi pas *a (soit le contenu de a) avec %s
affiche une chaine?
Parce que dans ce cas, *a (valeur pointée par a) désigne un caractère
et non une adresse ...
C :
Resultat : Segmentation fault
Resultat identique si *(Chaine+1), *(Chaine+2), *(Chaine+3) etc...
*(Chaine+9)
L'argument %s semble ici bloquer le déroulement du programme. Ca
paraît cohérent avec %c dans printf :
D :
Resultat : a
E:
Resultat : abc
F:
Resultat : bc
G :
Resultat : abc
Bah oui, normal. "%c" attend un int qui représente la valeur d'un
caractère. Si on lui donne ce qu'il attend, tout va bien...
1ere fois que je vois ce warning, je dois avouer que je n'avais pas
penser à appeler un tableau d'une chaine constante ou d'entier avec
l'adresse &. Le '&' est à mes yeux associé aux pointeurs.
Peut importe. La réalité est que & est un opérateur qui retourne une
valeur et un type. La valeur est l'adresse d'un objet. Le type
retourné est 'pointeur sur le type de l'objet'. Appliqué à un tableau ,
ça retourne l'adresse du tableau (comme en C, le premier élément d'un
tableau se trouve en [0], la valeur est la même qu'avec le nom du
tableau), mais le type est différent. Ailiet de retourner le type
'pointeur sur un élément du tableau', on retourne 'pointeur sur le
tableau' ce qui est très différent, et peut avoir des conséquences
terribles si on utilise un offset : Chaine + 1 n'a pas du tout la même
valeur que &Chaine+1.
A ma grande
surprise, le code fonctionne.
Oui, la valeur est la même. "Ça tombe en marche" ... Mais c'est faux
pour les raisons déjà expliquées.
En tant que débutant avec le langage C,
je trouve intéressant le warning: il montre bien qu'un tableau est un
pointeur vers le type de données dans lequel il a été définit/d éclaré
ici : char (*)[10], càd 10 pointeurs vers des données de type
caractères?
Oui, les warnings essayent d'aider à comprendre les subtilités du C...
Mais pourquoi tu ne fais pas du Pascal ...
H:
Resultat : abc
I :
Resultat : des carrés s'affichent : ` et abc
Je suppose que c'est la représentation d'emplacements mémoire (voir I )
J:
Resultat : 27776137614
Des comportements indéfinis ...
Le message confirme que ce sont bien 2 pointeurs sur char
Je suppose que c'est l'adresse de *Chaine2 représentée sous la forme
d'un entier?
Oui, en octal... Quelle idée. Le bon format pour une adresse est "%p"
et il faut forcer le paramètre 'adresse' en (void *)
K :
Resultat : abc
Je ne comprends pas l'erreur "invalid initializer". Pourtant le code
fonctionne même avec : *Chaine[0], *Chaine[20]...
certainement pas. C'est printf("n%c", *(Chaine2[1])) . Attention à la
préséance des opérateurs ...
L :
Resultat : abc
error: invalid initializer
error: expected expression before ] token
error: array subscript is not an integer
warning: format %c expects type int, but argument 2 has type char
*
Et pourtant ça fonctionne.
Invalid initializer est dans J alors je suppose que la réponse
précédente satisfait la question présente.
expected expression ... : je comprends que je dois mettre un indice
entre [ ] . Dans J, les indices ne me semblent pas utiles et ici, ils
seraient utiles?
array subscript is not an integer : je ne comprends pas
warning : format %c expects type int ... : selon moi, %c attend un
caractère et non pas un int ...
Nan. "%c" attend un int représentant la valeur d'un caractère.
M:
Resultat inédit : E#abc
warning: format %s expects type char *, but argument 2 has ty pe
char **
Je ne suis pas sûr de comprendre.
Il n'y a rien de prévu nativement pour représenter un tableau de
pointeurs.
D'autre part, il n'y a pas de type 'Char' en C standard. C'est 'char'.
printf("n%s", Chaine) ; /* A : OK */
Le 'n' indique la fin de ligne, il se place donc ... en fin de ligne !
printf ("%sn", Chaine); /* A : OK */
en effet, il force l'émission des caractères. Sinon, le caractères placés après risquent de ne pas être émis ...
printf("n%s", *Chaine) ; /* B : warning: format %s expects type char *, but argument 2 has type int ... Segmentation fault : */
Ben oui, normal. *Chaine ou *(Chaine + 0) ou encore Chaine[0], désigne un caractère (type char), qui est automatiquement converti en int. Cet int n'a quasiment aucune chance d'être une adresse valide ("%s" attends l'adresse d'une chaine de caractères). Tu veux peut être "%c" pour voir le caractère ?
printf("n%s", *(Chaine+0) ) ; /* C : warning: format %s expects type char *, but argument 2 has type int ... Segmentation fault : */
Même problème
printf("n%c", *(Chaine+0) ) ; /* D: OK */ printf("n%s", Chaine+0 ) ; /* E : OK */ printf("n%s", Chaine+1 ) ; /* F : OK */
printf("n%s", &Chaine ) ; /* G : warning: format %s expects type char *, but argument 2 has type char (*)[10] ... OK */
Non, pas OK. Le comportement est indéfini. On ne fait pas ça.
printf("n%s", &Chaine[0] ) ; /* H: OK */
/*CHAINE 2 */
printf("n%s", &Chaine2) ; /* I : warning: format %s expects type char *, but argument 2 has type char * (*)[2] ... résultat indéterminé*/
Oui, carrément n'importe quoi ...
printf("n%o", &Chaine2) ; /* J : warning: format %o expects type unsigned int, but argument 2 has type char * (*)[2] ... résult at : 27776137614 */
Pareil. Tu programmes au hasard ? Tu testes le compilateur ? Pourquoi "%o" ? Tu trouves que l'octal est adapté ?
printf("n%c", *Chaine2[1]) ; /* K : warning: format %c expects type int, but argument 2 has type char **... résultat : vid e */
Oui, portnawak ...
printf("n%s", Chaine2[0]) ; /* L : OK */
printf("n%s", Chaine2) ; /* M : warning: format %s expects type char *, but argument 2 has type char ** ...resultat : E#abc * /
Non, résultat indéfini, c'est tout ...
Il manque :
printf("%sn", Chaine2[1]) ; /* O : OK */
printf("nn") ;
Pas très utile si on prends soin de mettre le 'n' à la fin de l ligne, comme il se doit ...
return 0 ;
}
/* A : Resultat : abc
Je comprends ici que Chaine est un tableau (ou une chaine constante pour être plus précis?).
C'est un tableau de char initialisé modifiable. Sa valeur est {'a','b','c',0,0,0,0,0,0,0}
Le paragraphe suivant l'extrait du K&R précédent dis que lorsqu'un no m de tableau est envoyé à une fonction, c'est l'emplacement du 1er élément qui est envoyé...
Oui, c'est à dire une adresse. L'adresse du premier élément du tablea u si c'est le nom seul (<nom> ou <nom> + 0)
et à l'intérieur de cette fonction, cet argument est une variable locale
Oui, comme tous les arguments. Ici, c'est une variable locale de type 'adresse de char', dont un pointeur sur char (char *s, par exemple).
Je ne comprends pas que pour printf avec %s, * ou le contenu de
Chaine
ne soit pas appelé mais ce qui me semble être l'adresse en mémoire de Chaine comme lorsqu'on passe char *pointeur ; pointeur = Chaine ou pointeur = &Chaine[0]. Le point H va dans ce sens
Comme expliqué précédemment, "%s" attend l'adresse d'un tableau de char initialisé avec une chaine, donc terminée par un 0. Si on lui passe autre chose (*Chaine, par exemple), le comportement est indéfini.
Ce premier cas est celui qui me fait toujours réfléchir et peut me donner une erreur .
Y'a pas trop à réfléchir. Une fois qu'on sait ce qu'attend é%s", to ut est clair. Et c'est pareil avec scanf() (sauf que c'est la taille qui importe et non le contenu).
Surtout que dans ce cas scanf ajoute de l'insulte à la blessure car : scanf("%s", Chaine) au lieu de scanf("%s", &Chaine) comme on peut s'y attendre ;
Pourquoi & ? On a expliqué en long en large et travers que quand on passait le nom d'un tableau à une fonction, celui-ci était convertit en adresse du premier élément. On peut donc mettre :
scanf("%s", Chaine) ou scanf("%s", Chaine + 0) ou scanf("%s", &Chaine[0]) si on aime la complication.
Attention, cette saisie est dangereuse et pas paratique, car elle prend tout jusqu'au premier séparateur (espace, tab ou fin de ligne).
char Chaine[10] ; printf("nEntrez une chaine : ") ; scanf("%s", &Chaine[0]) OK MAIS scanf("%s", &Chaine) a ffiche warning: format %s expects type char *, but argument 2 has ty pe char (*)[10] mais la saisie se fait quand même
A tes risques et périls. Le comportement est indéterminé. On a déj à fort affaire avec les comportements normaux. Ne pas perdre de temps avec les comportements non définis ... Enfin, tu as voulu faire du C...
B : Resultat : Segmentation fault
Le warning dit que le 2ème argument est de type int. Ce n'est pas la première fois que j'ai ce message. Est-ce que je dois comprendre que dans printf, %s est le 1er argument, et *Chaine est le second?
Ben oui. C'est pas évident ?
Alors comme le pointeur *Chaine n'a pas été déclaré, *Chaine est de type int par défaut ?
Attention. Le rôle de * change selon le contexte.
Il sert
- soit d'opérateur de multiplication quand il est placé entre 2 opérandes : a * 2, a * b etc. - soit de déclarateur de pointeur dans une déclaration de variable : int *p; char const *s="hello" - soit d'opérateur de déréférencement quand il est appliqué à u n pointeur : inc c = *s, f (*s) etc.
ici, c'est le 3 ème cas. *Chaine est *(Chaine + 0), c'est à dire Chaine[0]. C'est donc un caractère qui n'a rien à voir avec une adresse. Le type est int, parce que l'appel de fonction avec un paramètre de type char est convertit en int.
Ensuite, le K et R dis pour pa = a ...un tableau constant a[i] peut aussi s'écrire *(a+i) pourquoi pas *a (soit le contenu de a) avec %s affiche une chaine?
Parce que dans ce cas, *a (valeur pointée par a) désigne un caractère et non une adresse ...
C : Resultat : Segmentation fault
Resultat identique si *(Chaine+1), *(Chaine+2), *(Chaine+3) etc... *(Chaine+9) L'argument %s semble ici bloquer le déroulement du programme. Ca paraît cohérent avec %c dans printf :
D : Resultat : a
E: Resultat : abc
F: Resultat : bc
G : Resultat : abc
Bah oui, normal. "%c" attend un int qui représente la valeur d'un caractère. Si on lui donne ce qu'il attend, tout va bien...
1ere fois que je vois ce warning, je dois avouer que je n'avais pas penser à appeler un tableau d'une chaine constante ou d'entier avec l'adresse &. Le '&' est à mes yeux associé aux pointeurs.
Peut importe. La réalité est que & est un opérateur qui retourne une valeur et un type. La valeur est l'adresse d'un objet. Le type retourné est 'pointeur sur le type de l'objet'. Appliqué à un tableau , ça retourne l'adresse du tableau (comme en C, le premier élément d'un tableau se trouve en [0], la valeur est la même qu'avec le nom du tableau), mais le type est différent. Ailiet de retourner le type 'pointeur sur un élément du tableau', on retourne 'pointeur sur le tableau' ce qui est très différent, et peut avoir des conséquences terribles si on utilise un offset : Chaine + 1 n'a pas du tout la même valeur que &Chaine+1.
A ma grande surprise, le code fonctionne.
Oui, la valeur est la même. "Ça tombe en marche" ... Mais c'est faux pour les raisons déjà expliquées.
En tant que débutant avec le langage C, je trouve intéressant le warning: il montre bien qu'un tableau est un pointeur vers le type de données dans lequel il a été définit/d éclaré ici : char (*)[10], càd 10 pointeurs vers des données de type caractères?
Oui, les warnings essayent d'aider à comprendre les subtilités du C... Mais pourquoi tu ne fais pas du Pascal ...
H: Resultat : abc
I : Resultat : des carrés s'affichent : ` et abc
Je suppose que c'est la représentation d'emplacements mémoire (voir I )
J: Resultat : 27776137614
Des comportements indéfinis ...
Le message confirme que ce sont bien 2 pointeurs sur char Je suppose que c'est l'adresse de *Chaine2 représentée sous la forme d'un entier?
Oui, en octal... Quelle idée. Le bon format pour une adresse est "%p" et il faut forcer le paramètre 'adresse' en (void *)
K : Resultat : abc
Je ne comprends pas l'erreur "invalid initializer". Pourtant le code fonctionne même avec : *Chaine[0], *Chaine[20]...
certainement pas. C'est printf("n%c", *(Chaine2[1])) . Attention à la préséance des opérateurs ...
L : Resultat : abc
error: invalid initializer error: expected expression before ] token error: array subscript is not an integer warning: format %c expects type int, but argument 2 has type char *
Et pourtant ça fonctionne. Invalid initializer est dans J alors je suppose que la réponse précédente satisfait la question présente. expected expression ... : je comprends que je dois mettre un indice entre [ ] . Dans J, les indices ne me semblent pas utiles et ici, ils seraient utiles? array subscript is not an integer : je ne comprends pas warning : format %c expects type int ... : selon moi, %c attend un caractère et non pas un int ...
Nan. "%c" attend un int représentant la valeur d'un caractère.
M: Resultat inédit : E#abc warning: format %s expects type char *, but argument 2 has ty pe char ** Je ne suis pas sûr de comprendre.
Il n'y a rien de prévu nativement pour représenter un tableau de pointeurs.
Antoine Leca
heron maladroit écrivit :
char Chaine[10] = "abc" ;
printf("n%s", Chaine) ; /* A : OK */ Resultat : abc
Je comprends ici que Chaine est un tableau (ou une chaine constante pour être plus précis?). Le paragraphe suivant l'extrait du K&R précédent dis que lorsqu'un nom de tableau est envoyé à une fonction, c'est l'emplacement du 1er élément qui est envoyé... et à l'intérieur de cette fonction, cet argument est une variable locale
Je ne comprends pas que pour printf avec %s, * ou le contenu de Chaine ne soit pas appelé mais ce qui me semble être l'adresse en mémoire de Chaine comme lorsqu'on passe char *pointeur ; pointeur = Chaine ou pointeur = &Chaine[0].
Bin il va falloir que tu comprennes cela avant de pousser plus loin, parce que tout en dépend...
Comme rappelé dans l'extrait du K&R, Chaine est un tableau ; il est donc jugé trop gros pour être passé au sous-programme : pour passer un paramètre il faut le copier dans un emplacement prédéfini avant l'appel, puis au début de la fonction le recopier depuis la zone de passage prédéfinie : cela s'appelle les conventions d'appel, et c'est très semblable au circuit que font tes valises lorsque tu prends l'avion : avant de monter dedans il te faut les enregistrer, puis elles sont mises dans la soute, et te sont restituées à destination : comme c'est très lourd, on préfère si possible utiliser les bagages de cabine, pardon les paramètres passés par registre, qui évite le circuit compliqué. Seulement les paramètres que l'on peut passer par registre sont limités en taille ; et un tableau n'est pas acceptable: donc on préfère passer un registre, en l'occurrence un pointeur vers la dite chaîne.
<LEÇON_SUIVANTE> SAUF QU'en faisant cela, on ne transporte plus réellement la valise, pardon, le tableau n'est pas réellement copié dans le sous-programme, on travaille non pas sur une copie locale mais sur le vrai tableau, seul et unique : cela est la cause profonde des « problèmes de pointeurs » en C: il faut constamment veiller à ne pas écraser les tableaux que l'on nous a passé en paramètres : d'où l'intérêt du mot-clé const, qui permet au compilateur de renforcer notre attention. </LEÇON_SUIVANTE>
Donc pour en revenir à printf(), il y a une différence fondamentale entre %i/%o/%c/%p d'un côté, qui imprime la valeur des paramètres passés comme variables locales pour printf, et %s de l'autre côté, qui imprime la valeur du tableau global, externe à printf et donc seulement connu de cette fonction par l'adresse à laquelle il commence.
Le point H va dans ce sens printf("n%s", &Chaine[0] ) ; /* H: OK */
Mmmm. Il faut dire que dans la plupart des cas, Chaine est équivalent à &Chaine[0] (les cas où ce n'est pas équivalent sont: derrière sizeof, derrière &, à gauche de = ou dans l'initialisation d'un objet).
Surtout que dans ce cas scanf ajoute de l'insulte à la blessure car : scanf("%s", Chaine) au lieu de scanf("%s", &Chaine) comme on peut s'y attendre ;
scanf() est une fonction différente de printf(), et soumise à d'autre contraintes : en particulier, pour que scanf("%i",???) fonctionne on ne peut plus se contenter de la valeur d'une variable _avant_ l'appel à scanf() dont on se moque éperdument : il faut que scanf() puisse _modifier_ la variable, et pour cela il est nécessaire de passer son adresse, autrement dit un pointeur vers sa position, à la fonction scanf scanf("%i", &i);
Seulement, comme expliqué ci-dessus, avec les chaînes on a déjà passé ce fameux pointeur, donc pour économiser on utilise directement le pointeur scanf("%s", &Chaine[0]); ou, ce qui est équivalent scanf("%s", Chaine);
scanf("%s", &Chaine) affiche warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[10]’
J'espère que tu vois pourquoi maintenant.
mais la saisie se fait quand même
Je ne pense pas. Au mieux, la saisie va s'effectuer en écrasant des données inutiles sur la pile de main(), et il n'y aura pas de conséquences graves (mais la chaîne entrée au clavier ne sera pas dans Chaine) ; au pire, tu vas avoir droit à un SIGSEGV pour avoir écraser tes propres variables...
printf("n%s", *Chaine) ; /* B : warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’ ... Segmentation fault : */ Resultat : Segmentation fault
Si tu as bien suivi, c'est la même chose dans l'autre sens : cette fois-ci tu n'essaye pas d'écrire dans ta pile, mais tu fais croire à printf() que le caractère 'a' est l'adresse où se trouve la chaîne à écrire...
Le warning dit que le 2ème argument est de type int. Ce n'est pas la première fois que j'ai ce message. Est-ce que je dois comprendre que dans printf, %s est le 1er argument, et *Chaine est le second?
Oui.
Alors comme le pointeur *Chaine n'a pas été déclaré,
Bin si (sauf que ce n'est pas un pointeur) : l'objet Chaine est déclaré comme tableau de char, donc lorsqu'on utilise l'opérateur * qui en extrait le premier élément, on obtient le premier élément du tableau, et le type du résultat est char. Au niveau des conventions d'appel, char est trop petit, donc on l'agrandit en int, ce qui explique le message ci-dessus
Là aussi, on est dans les choses de base concernant les pointeurs (en l'occurrence, ne pas confondre l'opérateur * avec l'utilisation de * pour déclarer des pointeurs), il faut absolument que tu maîtrises cela avant de prétendre aller plus loin.
Antoine
heron maladroit écrivit :
char Chaine[10] = "abc" ;
printf("n%s", Chaine) ; /* A : OK */
Resultat : abc
Je comprends ici que Chaine est un tableau (ou une chaine constante
pour être plus précis?).
Le paragraphe suivant l'extrait du K&R précédent dis que lorsqu'un nom
de tableau est envoyé à une fonction, c'est l'emplacement du
1er élément qui est envoyé... et à l'intérieur de cette fonction, cet
argument est une variable locale
Je ne comprends pas que pour printf avec %s, * ou le contenu de Chaine
ne soit pas appelé mais ce qui me semble être l'adresse en mémoire de
Chaine comme lorsqu'on passe char *pointeur ; pointeur = Chaine ou
pointeur = &Chaine[0].
Bin il va falloir que tu comprennes cela avant de pousser plus loin,
parce que tout en dépend...
Comme rappelé dans l'extrait du K&R, Chaine est un tableau ; il est donc
jugé trop gros pour être passé au sous-programme : pour passer un
paramètre il faut le copier dans un emplacement prédéfini avant l'appel,
puis au début de la fonction le recopier depuis la zone de passage
prédéfinie : cela s'appelle les conventions d'appel, et c'est très
semblable au circuit que font tes valises lorsque tu prends l'avion :
avant de monter dedans il te faut les enregistrer, puis elles sont mises
dans la soute, et te sont restituées à destination : comme c'est très
lourd, on préfère si possible utiliser les bagages de cabine, pardon les
paramètres passés par registre, qui évite le circuit compliqué.
Seulement les paramètres que l'on peut passer par registre sont limités
en taille ; et un tableau n'est pas acceptable: donc on préfère passer
un registre, en l'occurrence un pointeur vers la dite chaîne.
<LEÇON_SUIVANTE>
SAUF QU'en faisant cela, on ne transporte plus réellement la valise,
pardon, le tableau n'est pas réellement copié dans le sous-programme, on
travaille non pas sur une copie locale mais sur le vrai tableau, seul et
unique : cela est la cause profonde des « problèmes de pointeurs » en C:
il faut constamment veiller à ne pas écraser les tableaux que l'on nous
a passé en paramètres : d'où l'intérêt du mot-clé const, qui permet au
compilateur de renforcer notre attention.
</LEÇON_SUIVANTE>
Donc pour en revenir à printf(), il y a une différence fondamentale
entre %i/%o/%c/%p d'un côté, qui imprime la valeur des paramètres passés
comme variables locales pour printf, et %s de l'autre côté, qui imprime
la valeur du tableau global, externe à printf et donc seulement connu de
cette fonction par l'adresse à laquelle il commence.
Le point H va dans ce sens
printf("n%s", &Chaine[0] ) ; /* H: OK */
Mmmm. Il faut dire que dans la plupart des cas, Chaine est équivalent à
&Chaine[0] (les cas où ce n'est pas équivalent sont: derrière sizeof,
derrière &, à gauche de = ou dans l'initialisation d'un objet).
Surtout que dans ce cas scanf ajoute de l'insulte
à la blessure car : scanf("%s", Chaine) au lieu de scanf("%s", &Chaine)
comme on peut s'y attendre ;
scanf() est une fonction différente de printf(), et soumise à d'autre
contraintes : en particulier, pour que scanf("%i",???) fonctionne on ne
peut plus se contenter de la valeur d'une variable _avant_ l'appel à
scanf() dont on se moque éperdument : il faut que scanf() puisse
_modifier_ la variable, et pour cela il est nécessaire de passer son
adresse, autrement dit un pointeur vers sa position, à la fonction scanf
scanf("%i", &i);
Seulement, comme expliqué ci-dessus, avec les chaînes on a déjà passé ce
fameux pointeur, donc pour économiser on utilise directement le pointeur
scanf("%s", &Chaine[0]);
ou, ce qui est équivalent
scanf("%s", Chaine);
scanf("%s", &Chaine) affiche
warning: format ‘%s’ expects type ‘char *’, but argument 2 has type
‘char (*)[10]’
J'espère que tu vois pourquoi maintenant.
mais la saisie se fait quand même
Je ne pense pas. Au mieux, la saisie va s'effectuer en écrasant des
données inutiles sur la pile de main(), et il n'y aura pas de
conséquences graves (mais la chaîne entrée au clavier ne sera pas dans
Chaine) ; au pire, tu vas avoir droit à un SIGSEGV pour avoir écraser
tes propres variables...
printf("n%s", *Chaine) ; /* B : warning: format ‘%s’ expects type
‘char *’, but argument 2 has type ‘int’ ... Segmentation fault : */
Resultat : Segmentation fault
Si tu as bien suivi, c'est la même chose dans l'autre sens : cette
fois-ci tu n'essaye pas d'écrire dans ta pile, mais tu fais croire à
printf() que le caractère 'a' est l'adresse où se trouve la chaîne à
écrire...
Le warning dit que le 2ème argument est de type int.
Ce n'est pas la première fois que j'ai ce message. Est-ce que je dois
comprendre que dans printf, %s est le 1er argument, et *Chaine est le
second?
Oui.
Alors comme le pointeur *Chaine n'a pas été déclaré,
Bin si (sauf que ce n'est pas un pointeur) : l'objet Chaine est déclaré
comme tableau de char, donc lorsqu'on utilise l'opérateur * qui en
extrait le premier élément, on obtient le premier élément du tableau, et
le type du résultat est char.
Au niveau des conventions d'appel, char est trop petit, donc on
l'agrandit en int, ce qui explique le message ci-dessus
Là aussi, on est dans les choses de base concernant les pointeurs (en
l'occurrence, ne pas confondre l'opérateur * avec l'utilisation de *
pour déclarer des pointeurs), il faut absolument que tu maîtrises cela
avant de prétendre aller plus loin.
printf("n%s", Chaine) ; /* A : OK */ Resultat : abc
Je comprends ici que Chaine est un tableau (ou une chaine constante pour être plus précis?). Le paragraphe suivant l'extrait du K&R précédent dis que lorsqu'un nom de tableau est envoyé à une fonction, c'est l'emplacement du 1er élément qui est envoyé... et à l'intérieur de cette fonction, cet argument est une variable locale
Je ne comprends pas que pour printf avec %s, * ou le contenu de Chaine ne soit pas appelé mais ce qui me semble être l'adresse en mémoire de Chaine comme lorsqu'on passe char *pointeur ; pointeur = Chaine ou pointeur = &Chaine[0].
Bin il va falloir que tu comprennes cela avant de pousser plus loin, parce que tout en dépend...
Comme rappelé dans l'extrait du K&R, Chaine est un tableau ; il est donc jugé trop gros pour être passé au sous-programme : pour passer un paramètre il faut le copier dans un emplacement prédéfini avant l'appel, puis au début de la fonction le recopier depuis la zone de passage prédéfinie : cela s'appelle les conventions d'appel, et c'est très semblable au circuit que font tes valises lorsque tu prends l'avion : avant de monter dedans il te faut les enregistrer, puis elles sont mises dans la soute, et te sont restituées à destination : comme c'est très lourd, on préfère si possible utiliser les bagages de cabine, pardon les paramètres passés par registre, qui évite le circuit compliqué. Seulement les paramètres que l'on peut passer par registre sont limités en taille ; et un tableau n'est pas acceptable: donc on préfère passer un registre, en l'occurrence un pointeur vers la dite chaîne.
<LEÇON_SUIVANTE> SAUF QU'en faisant cela, on ne transporte plus réellement la valise, pardon, le tableau n'est pas réellement copié dans le sous-programme, on travaille non pas sur une copie locale mais sur le vrai tableau, seul et unique : cela est la cause profonde des « problèmes de pointeurs » en C: il faut constamment veiller à ne pas écraser les tableaux que l'on nous a passé en paramètres : d'où l'intérêt du mot-clé const, qui permet au compilateur de renforcer notre attention. </LEÇON_SUIVANTE>
Donc pour en revenir à printf(), il y a une différence fondamentale entre %i/%o/%c/%p d'un côté, qui imprime la valeur des paramètres passés comme variables locales pour printf, et %s de l'autre côté, qui imprime la valeur du tableau global, externe à printf et donc seulement connu de cette fonction par l'adresse à laquelle il commence.
Le point H va dans ce sens printf("n%s", &Chaine[0] ) ; /* H: OK */
Mmmm. Il faut dire que dans la plupart des cas, Chaine est équivalent à &Chaine[0] (les cas où ce n'est pas équivalent sont: derrière sizeof, derrière &, à gauche de = ou dans l'initialisation d'un objet).
Surtout que dans ce cas scanf ajoute de l'insulte à la blessure car : scanf("%s", Chaine) au lieu de scanf("%s", &Chaine) comme on peut s'y attendre ;
scanf() est une fonction différente de printf(), et soumise à d'autre contraintes : en particulier, pour que scanf("%i",???) fonctionne on ne peut plus se contenter de la valeur d'une variable _avant_ l'appel à scanf() dont on se moque éperdument : il faut que scanf() puisse _modifier_ la variable, et pour cela il est nécessaire de passer son adresse, autrement dit un pointeur vers sa position, à la fonction scanf scanf("%i", &i);
Seulement, comme expliqué ci-dessus, avec les chaînes on a déjà passé ce fameux pointeur, donc pour économiser on utilise directement le pointeur scanf("%s", &Chaine[0]); ou, ce qui est équivalent scanf("%s", Chaine);
scanf("%s", &Chaine) affiche warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[10]’
J'espère que tu vois pourquoi maintenant.
mais la saisie se fait quand même
Je ne pense pas. Au mieux, la saisie va s'effectuer en écrasant des données inutiles sur la pile de main(), et il n'y aura pas de conséquences graves (mais la chaîne entrée au clavier ne sera pas dans Chaine) ; au pire, tu vas avoir droit à un SIGSEGV pour avoir écraser tes propres variables...
printf("n%s", *Chaine) ; /* B : warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’ ... Segmentation fault : */ Resultat : Segmentation fault
Si tu as bien suivi, c'est la même chose dans l'autre sens : cette fois-ci tu n'essaye pas d'écrire dans ta pile, mais tu fais croire à printf() que le caractère 'a' est l'adresse où se trouve la chaîne à écrire...
Le warning dit que le 2ème argument est de type int. Ce n'est pas la première fois que j'ai ce message. Est-ce que je dois comprendre que dans printf, %s est le 1er argument, et *Chaine est le second?
Oui.
Alors comme le pointeur *Chaine n'a pas été déclaré,
Bin si (sauf que ce n'est pas un pointeur) : l'objet Chaine est déclaré comme tableau de char, donc lorsqu'on utilise l'opérateur * qui en extrait le premier élément, on obtient le premier élément du tableau, et le type du résultat est char. Au niveau des conventions d'appel, char est trop petit, donc on l'agrandit en int, ce qui explique le message ci-dessus
Là aussi, on est dans les choses de base concernant les pointeurs (en l'occurrence, ne pas confondre l'opérateur * avec l'utilisation de * pour déclarer des pointeurs), il faut absolument que tu maîtrises cela avant de prétendre aller plus loin.