Tableau et pointeur.

Le
Xavier Combelle
Bonjour a tous,

D'habitude, lorsque je passe des tableau
de caractères en paramètre, je les passe
a des fonctions dont le prototype est: void f(char *t).
Mais dans le cas qui nous occupe,
je ne peux pas modifier le prototype
de certaine fonctions.
Pour que mon code fonctionne, je dois
retirer le '&' par rapport
à ce que je pensais être le
passage de paramètre par référence correct.
Quelqu'un peut-il m'expliquer pourquoi ?
Quelqu'un peut-il me donner une solution
pour que le code fonctionne, de facon "logique"
et sans utiliser de char* ?

Xavier


#include <stdio.h>
typedef char tTableau [10];
tTableau *a_afficher;

/* prototype fixe */
void Afficher(void) {
printf("valeur : %s" , *a_afficher);
}
/* j'ai le droit de modifier
le prototype de cette fonction */
static void Appele(tTableau *t)
{ a_afficher = t;
Afficher();}

/* prototype fixe */
void Fonction1( tTableau t)
{ printf ("f1: fonctionne"); Appele (t);
printf ("f1: en panne"); Appele( &t); }
/* prototype fixe */
void Fonction2(tTableau *t)
{printf("f2: "); Appele(t); }

int main ()
{
tTableau val = "hello";
Fonction1(val);
Fonction2(&val);
return 0;
}


pour info, voici le resultat de la compilation
et de l'execution.

% gcc -o tab -ansi -pedantic -Wall -W tab.c
tab.c: In function `Fonction1':
tab.c:12: warning: passing arg 1 of `Appele' from incompatible pointer type
tab.c:13: warning: passing arg 1 of `Appele' from incompatible pointer type
% tab
f1: fonctionne
valeur : hello
f1: en panne
valeur : Ð÷ÿ¿<øÿ¿è÷ÿ¿lhello
f2:
valeur : hello
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Régis Troadec
Le #624646
"Xavier Combelle" news:40976db9$0$17919$

Bonjour a tous,


Salut,

D'habitude, lorsque je passe des tableau
de caractères en paramètre, je les passe
a des fonctions dont le prototype est: void f(char *t).
Mais dans le cas qui nous occupe,
je ne peux pas modifier le prototype
de certaine fonctions.
Pour que mon code fonctionne, je dois
retirer le '&' par rapport
à ce que je pensais être le
passage de paramètre par référence correct.
Quelqu'un peut-il m'expliquer pourquoi ?
Quelqu'un peut-il me donner une solution
pour que le code fonctionne, de facon "logique"
et sans utiliser de char* ?


Ce n'est généralement pas très bon de cacher les pointeurs (ni les
tableaux), à moins AMHA de définir son propre ADT et d'avoir fourni vraiment
toutes les opérations nécessaires s'y rapportant. Par contre, un #define
pour une taille de tableau plutot que 10, c'est bien.

Xavier


#include typedef char tTableau [10];
tTableau *a_afficher;


a_afficher est un pointeur sur tableau de char (j'aurais préféré
#define MAX 10
char (*a_afficher)[MAX]; ),

/* prototype fixe */
void Afficher(void) {
printf("valeur : %sn" , *a_afficher);
}


OK.

/* j'ai le droit de modifier
le prototype de cette fonction */
static void Appele(tTableau *t)
{ a_afficher = t;
Afficher();}


OK.

/* prototype fixe */
void Fonction1( tTableau t)
{ printf ("f1: fonctionnen"); Appele (t);


t est de type tableau de char, pas de type pointeur sur tableau de char,
types incompatibles.

printf ("f1: en pannen"); Appele( &t); }


Avec les tableaux, le nom du tableau représente déjà l'adresse du premier
élément, t est équivalent à &t[0]. Je crois même que c'est un UB ici, t
n'est pas une lvalue, tu ne peux pas appliquer l'opérateur de prise
d'adresse &.

Appele( &t[0]); marche mais le type est toujours incompatible comme avec le
premier printf, car Appele prend un pointeur de tableau en paramètre. Le
mieux, c'est d'utiliser uniquement le type tTableau, sans pointeurs.

Si ca marche, c'est que t est promu en pointeur sur tableau (tTableau) lors
de l'appel de Appele mais reste l'adresse du premier élément de t.
L'indirection est alors valide dans Afficher.

/* prototype fixe */
void Fonction2(tTableau *t)
{printf("f2: n"); Appele(t); }


OK.

int main ()
{
tTableau val = "hello";
Fonction1(val);
Fonction2(&val);
return 0;
}



Selon ce que tu veux, voici un changement dans Fonction1 (tu ne peux pas
toucher aux prototypes mais tu peux modifier les contenus, non?) :

void Fonction1(tTableau t)
{
/* pas oublier stdlib.h*/
tTableau * p = malloc(sizeof*p);
if (p!=NULL)
{
/* pas oublier string.h*/
strncpy(*p, t, sizeof tTableau/sizeof tTableau[0] - 1);
printf("f1: fonctionnen");
Appele(p);
free(p);
}
}


Regis

Antoine Leca
Le #624642
En c785g0$pr1$, Régis Troadec va escriure:
typedef char tTableau [10];
void Fonction1( tTableau t)


t est de type tableau de char, [...]


Non. t est de type pointeur vers char.
(Et on devrait pendre celui qui force ce genre de prototype).


printf ("f1: en pannen"); Appele( &t); }


Avec les tableaux,


Quel tableau ? ;-)


Antoine


Yves ROMAN
Le #624641

"Xavier Combelle" news:40976db9$0$17919$

Bonjour a tous,


Salut,

D'habitude, lorsque je passe des tableau
de caractères en paramètre, je les passe
a des fonctions dont le prototype est: void f(char *t).
Mais dans le cas qui nous occupe,
je ne peux pas modifier le prototype
de certaine fonctions.
Pour que mon code fonctionne, je dois
retirer le '&' par rapport
à ce que je pensais être le
passage de paramètre par référence correct.
Quelqu'un peut-il m'expliquer pourquoi ?
Quelqu'un peut-il me donner une solution
pour que le code fonctionne, de facon "logique"
et sans utiliser de char* ?


Ce n'est généralement pas très bon de cacher les pointeurs (ni les
tableaux), à moins AMHA de définir son propre ADT et d'avoir fourni vraiment
toutes les opérations nécessaires s'y rapportant. Par contre, un #define
pour une taille de tableau plutot que 10, c'est bien.

Xavier


#include typedef char tTableau [10];
tTableau *a_afficher;


a_afficher est un pointeur sur tableau de char (j'aurais préféré
#define MAX 10
char (*a_afficher)[MAX]; ),

/* prototype fixe */
void Afficher(void) {
printf("valeur : %sn" , *a_afficher);



Remarque : ici
printf("valeur : %sn" , a_afficher);
marche aussi : un pointeur sur un tTableau contient l'adresse de son 1er élément

}


OK.

/* j'ai le droit de modifier
le prototype de cette fonction */
static void Appele(tTableau *t)
{ a_afficher = t;
Afficher();}


OK.

/* prototype fixe */
void Fonction1( tTableau t)
{ printf ("f1: fonctionnen"); Appele (t);


t est de type tableau de char, pas de type pointeur sur tableau de char,
types incompatibles.

printf ("f1: en pannen"); Appele( &t); }


Avec les tableaux, le nom du tableau représente déjà l'adresse du premier
élément, t est équivalent à &t[0]. Je crois même que c'est un UB ici, t
n'est pas une lvalue, tu ne peux pas appliquer l'opérateur de prise
d'adresse &.

Appele( &t[0]); marche mais le type est toujours incompatible comme avec le
premier printf, car Appele prend un pointeur de tableau en paramètre. Le
mieux, c'est d'utiliser uniquement le type tTableau, sans pointeurs.

Si ca marche, c'est que t est promu en pointeur sur tableau (tTableau) lors
de l'appel de Appele mais reste l'adresse du premier élément de t.
L'indirection est alors valide dans Afficher.


Les messages d'erreur sous Solaris sont un peu plus explicites
"test5.c", line 25: warning: argument #1 is incompatible with prototype:
prototype: pointer to array[10] of char : "test5.c", line 14
argument : pointer to char
"test5.c", line 26: warning: argument #1 is incompatible with prototype:
prototype: pointer to array[10] of char : "test5.c", line 14
argument : pointer to pointer to char
Il montrent que pour le compilateur, le prototype de ta fonction est traité
comme
void Fonction1( char * t)
(On voit mal comment satisfaire le compilateur.)

Appele( &t) passe alors l'adresse de l'argument de la fonction.
En rajoutant un parametre avant et après, et rajoutant des printf(%p) par ci par

tu obtiens :

void Afficher(void) {
printf("af=%pn",a_afficher) ;
printf("valeur : %sn" , *a_afficher);
}

/* prototype fixe */
void Fonction1( int i , tTableau t , int j )
{
printf("t1=%pn",t) ;
printf("&i=%p &t1=%p &j=%pn",&i,&t,&j) ;
printf ("f1: fonctionnen"); Appele (t);
printf ("f1: en pannen"); Appele( &t);
}

Fonction1(1,val,2);

&valïffd222
t1ïffd222
&iïffd204 &t1ïffd208 &jïffd20c
f1: fonctionne
afïffd222
valeur : hello
f1: en panne
afïffd208
valeur : ïÿÒ"
t2ïffd222
f2:
afïffd222
valeur : hello


/* prototype fixe */
void Fonction2(tTableau *t)
{printf("f2: n"); Appele(t); }


OK.

int main ()
{
tTableau val = "hello";
Fonction1(val);
Fonction2(&val);
return 0;
}






Emmanuel Delahaye
Le #624370
In 'fr.comp.lang.c', Xavier Combelle
D'habitude, lorsque je passe des tableau
de caractères en paramètre, je les passe
a des fonctions dont le prototype est: void f(char *t).


Pour être précis, tu passes l'adresse du tableau à la fonction via un
paramètre pointeur du même type.

Mais dans le cas qui nous occupe,
je ne peux pas modifier le prototype
de certaine fonctions.
Pour que mon code fonctionne, je dois
retirer le '&' par rapport
à ce que je pensais être le
passage de paramètre par référence correct.


Il n'y a pas de passage par référence en C. Tu confonds avec un autre
langage.

Quelqu'un peut-il m'expliquer pourquoi ?
Quelqu'un peut-il me donner une solution
pour que le code fonctionne, de facon "logique"
et sans utiliser de char* ?


Heu... Je ne connais pas d'autre moyen que le paramètre pointeur pour passer
une adresse. Si tu veux autre chose, il faut un autre langage que le C.

#include typedef char tTableau [10];


En principe, on évite ça...

tTableau *a_afficher;


Une globale? Quelle horreur!

/* prototype fixe */
void Afficher(void) {
printf("valeur : %sn" , *a_afficher);
}


Pouah!

/* j'ai le droit de modifier
le prototype de cette fonction */
static void Appele(tTableau *t)
{ a_afficher = t;
Afficher();}


Moui... Pas bô la globale...

/* prototype fixe */
void Fonction1( tTableau t)


't' est un pointeur implicite. Horrible, et confusant... Rendez moi mon
pointeur. Un programmeur C n'a pas honte de ses pointeurs. Il ne les cache
pas. Si tu veux un langage sans pointeurs visibles, choisit un autre langage.

{ printf ("f1: fonctionnen"); Appele (t);


OK. t est un pointeur de type char*

printf ("f1: en pannen"); Appele( &t); }


KO. Mauvais type ((char *)[10]). Pourquoi ce '&' ?

/* prototype fixe */
void Fonction2(tTableau *t)


Pointeur de pointeur? Est-ce bien raisonnable?

{printf("f2: n"); Appele(t); }

int main ()
{
tTableau val = "hello";
Fonction1(val);
Fonction2(&val);
return 0;
}


pour info, voici le resultat de la compilation
et de l'execution.

% gcc -o tab -ansi -pedantic -Wall -W tab.c
tab.c: In function `Fonction1':
tab.c:12: warning: passing arg 1 of `Appele' from incompatible pointer type
tab.c:13: warning: passing arg 1 of `Appele' from incompatible pointer type
% tab
f1: fonctionne
valeur : hello
f1: en panne
valeur : Ð÷ÿ¿<øÿ¿è÷ÿ¿lhello
f2:
valeur : hello


Mal à la tête...

Ceci fonctionne:

#include #include
typedef char tTableau[10];
tTableau a_afficher;

/* prototype fixe */
void Afficher (void)
{
printf ("valeur : %sn", a_afficher);
}

static void Appele (tTableau t)
{
memcpy (a_afficher, t, sizeof a_afficher);
Afficher ();
}

/* prototype fixe */
void Fonction1 (tTableau t)
{
printf ("f1: fonctionnen");
Appele (t);
}

int main ()
{
tTableau val = "hello";
Fonction1 (val);
return 0;
}

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?libÉ9
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Emmanuel Delahaye
Le #624369
In 'fr.comp.lang.c', "Régis Troadec"
Par contre,
un #define pour une taille de tableau plutot que 10, c'est bien.


Bof... L'endroit idéal pour définir la taille d'un tableau est sa définition.

int a[123];

Ensuite tout est mis en oeuvre pour transmettre cette information à qui de
droit par paramètres, ou structure adéquate, sans utiliser de constante
globale. Ca, c'est "bien".

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?libÉ9
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Régis Troadec
Le #624368
"Antoine Leca" news:c78d1p$dp2$

Salut,

En c785g0$pr1$, Régis Troadec va escriure:
typedef char tTableau [10];
void Fonction1( tTableau t)


t est de type tableau de char, [...]


Non. t est de type pointeur vers char.


Oui, j'ai zappé l'ajustement [] en * à l'appel de la fonction. M'enfin, ca
ne change pas trop le discours (il n'y a pas d'UB), pour ce qui est de
pointeur de tableau vers char, ca reste, les tableau de char sont a changer
en pointeur vers char.

(Et on devrait pendre celui qui force ce genre de prototype).


Oui, et avec une corde bien solide.

Regis



Régis Troadec
Le #624365
Erratum dans le sujet du message precedent, je voulais parler de typedef,
mais non, c'est avorté.
Horst Kraemer
Le #624364
On Tue, 04 May 2004 12:20:46 +0200, Xavier Combelle


Bonjour a tous,

D'habitude, lorsque je passe des tableau
de caractères en paramètre, je les passe
a des fonctions dont le prototype est: void f(char *t).
Mais dans le cas qui nous occupe,
je ne peux pas modifier le prototype
de certaine fonctions.


Pas de problème.


void fonction(tTableau);


est équivalent à

void fonction(char*);

Donc tu fais ton programme autour de ces fonctions comme si elles
étaient déclarées avec un paramêtre du type char*.

Pour que mon code fonctionne, je dois
retirer le '&' par rapport
à ce que je pensais être le
passage de paramètre par référence correct.
Quelqu'un peut-il m'expliquer pourquoi ?


Ce que tu fais n'est pas logique. Si le paramêtre avait le type int tu
passerais un int et non l'adresse d'un int. Ici le paramètre a l'air
d'avoir le type tTableau et tu passes l'adresse d'un tTableau et non
un tTableau. Pourquoi? (En fait l'écriture ment et le paramètre n'a
*pas* le type tTableau mais le type char*, et quand tu passes un
tTableau tu ne passes pas un tTableau mais un char*. Tu vois que les
mensonges de C sont logiques ;-)

--
Horst

Xavier Combelle
Le #624078
Ce n'est généralement pas très bon de cacher les pointeurs (ni les
tableaux), à moins AMHA de définir son propre ADT
Ca veut dire quoi ADT ?


Avec les tableaux, le nom du tableau représente déjà l'adresse du premier
élément, t est équivalent à &t[0]. Je crois même que c'est un UB ici, t
n'est pas une lvalue, tu ne peux pas appliquer l'opérateur de prise
d'adresse &.

Ca veut dire quoi UB?


Xavier Combelle
Le #624077
Rebonjour à tous,

Merci de vos réponses
Après une lecture attentive de vos réponse,
j'ai un peu avancé, mais c'est encore obscur.

D'après ce que j'ai compris,
le type tTableau est équivalent à un char *.
J'ai donc effectué la substitution suivante dans mon code:
partout ou j'avais un tTableau (sauf aux définitions
de variables), je l'ai remplacé par char*.
Maintenant, les cas ou ca fonctionne et les cas
où c'est en panne sont inverse par rapport au cas
initial.
Je soupconne donc qu'un tTableau ou un char*
ne fonctionnent pas tout à fait identiquement.
Mais je ne vois toujours pas pourquoi.

voici le code que j'ai obtenu:

#include typedef char tTableau [10];
char **a_afficher;

/* prototype fixe */
void Afficher(void) {
printf("valeur : %sn" , *a_afficher);
}
/* j'ai le droit de modifier
le prototype de cette fonction */
static void Appele(char **t)
{ a_afficher = t;
Afficher();}

/* prototype fixe */
void Fonction1( char *t)
{ printf ("f1: en pannen"); Appele( &t);
printf ("f1: fonctionnen"); Appele (t);
}
/* prototype fixe */
void Fonction2(char **t)
{printf("f2: n"); Appele(t); }

int main ()
{
tTableau val = "hello";
Fonction1(val);
Fonction2(&val);
return 0;
}
Publicité
Poster une réponse
Anonyme