Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Tableau et pointeur.

19 réponses
Avatar
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\n" , *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\n"); Appele (t);
printf ("f1: en panne\n"); Appele( &t); }
/* prototype fixe */
void Fonction2(tTableau *t)
{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

10 réponses

1 2
Avatar
Régis Troadec
"Xavier Combelle" a écrit dans le message de
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 <stdio.h>
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

Avatar
Antoine Leca
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


Avatar
Yves ROMAN

"Xavier Combelle" a écrit dans le message de
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 <stdio.h>
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;
}






Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Xavier Combelle wrote:
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 <stdio.h>
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 <stdio.h>
#include <string.h>

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/

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', "Régis Troadec" wrote:

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/

Avatar
Régis Troadec
"Antoine Leca" a écrit dans le message de
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



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


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

Avatar
Xavier Combelle
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?


Avatar
Xavier Combelle
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 <stdio.h>
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;
}
1 2