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

9 réponses

1 2
Avatar
Antoine Leca
En 4098b309$0$17900$, Xavier Combelle va escriure:
D'après ce que j'ai compris,
le type tTableau est équivalent à un char *.


Uniquement dans un prototype. Pas ailleurs.

Je soupconne donc qu'un tTableau ou un char*
ne fonctionnent pas tout à fait identiquement.


Non. Il faut distinguer trois cas:
- dans une définition de variable, un tableau réserve de l'espace pour son
contenu, pas un pointeur (c'est tout l'intérêt des tableaux); en conséquence
sizeof est différent.
- dans les prototypes de fonctions, un paramètre tableau cela n'existe pas,
c'est toujours un pointeur (et l'argument sera un pointeur vers le premier
élément du tableau si tu passes un tableau à la fonction; ça, c'est tout
l'intérêt du C). Attention, ce n'est pas récursif, un tableau de tableau va
devenir un pointeur vers un tableau, _pas_ un pointeur double.
- ailleurs, un tableau, c'est un pointeur avec des restrictions (pas le
même type, on ne peut pas lui affecter quelque chose, etc.)

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


Comprend pas. Je croyais que tu ne pouvais pas modifier les prototypes?


Antoine

Avatar
Régis Troadec
"Xavier Combelle" a écrit dans le message de
news:4098ade3$0$17900$

Salut,

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 ?



Terme anglophone (Abstract Data Type), ou en francais type de données
abstrait (TDA). Il s'agit d'un type de données (ensemble de valeurs et
d'opérations pouvant être réalisées sur ces valeurs) pour lequel on fournit
une interface d'accès et de manipulation devant être unique et complète
(exples : files, piles, arbres, etc...).

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?



Unspecified Behavior (comportement non spécifié par le standard, c.a.d. que
ce dernier définit un ensemble fini de comportements pouvant survenir suite
à une contruction hasardeuse dans le programme) ou Undefined Behavior
(comportement non défini par le standard, c.a.d. que ce dernier ne définit
RIEN sur le comportement pouvant survenir suite à une contruction hasardeuse
dans le programme, e.g. tout peut arriver, crash, etc....). Les deux sont à
bannir.

Regis


Avatar
Jean-Marc Bourguet
Xavier Combelle writes:

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


Il faut distinguer deux choses: les types et les variables de ce type.

Un type tableau est un type pas tout a fait comme les autres. On ne
peut ni le passer, ni le retourner par valeur directement par exemple.
Si on tente de le retourner, on a une erreur, si on tente de le
passer, en fait c'est comme si le premier niveau etait un pointeur (et
on peut omettre la taille dans ce cas).

Donc
void f(char t[]);
et
void f(char t[5]);
et
void f(char *t);
c'est la meme chose. Si on fait t++, on pointe alors vers le char
suivant.

void f(char (*t)[]);
est interdit a cause du manque de la taille.

void f(char (*t)[5]);
est une fonction demandant un pointeur vers un tableau de 5 char. Si
on fait t++, on pointe alors vers le tableau suivant (donc 5 char plus
loin).


Une variable de type tableau est une variable pas tout a fait comme
les autres. Dans un certain nombre de contextes, elle est transformee
en un pointeur vers le premier element du tableau. Entre autres quand
elle est passee en argument d'une fonction.


Pour augmenter la confusion, la notation a[b] est equivalente a *(a+b)
et a et b sont des contextes ou une variable tableau est convertie en
un pointeur vers le premier element.


En resume, tableau et pointeur c'est pas la meme chose et sont
suffisemment different pour que le penser entraine de la confusion.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Régis Troadec
"Xavier Combelle" a écrit dans le message de
news:4098b309$0$17900$
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 *.


Ah non, tTableau est un type tableau, de même que pour tTableau t; t est est
un tableau.
C'est un peu plus complexe :
dans un prototype de fontion void fonct(tTableau param); param est
transformé en 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];


Décidément pas beau, mais bon.

char **a_afficher;


Une variable globale, ce n'est pas joli non plus.

[coupé]


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


t est un pointeur vers char et Appele prend un pointeur vers un pointeur
vers char. L'adresse du premier élément de t est transmise successivement
dans Appele et dans Afficher, mais une fois rendu dans cette dernière, lors
du déréférencement (*a_afficher), c'est un caractère et pas une chaine de
caractères que tu obtiens. Ca peut planter (chez moi ca plante), et là il
s'agit d'un comportement indéfini (car %s attend une chaine terminée par
'').

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


OK

Regis

Avatar
Xavier Combelle
D'après ce que j'ai compris,
le type tTableau est équivalent à un char *.
Ah non, tTableau est un type tableau, de même que pour tTableau t; t est est

un tableau.
Donc ca doit être en faisant cette supposition que je me suis giourré

C'est un peu plus complexe :
dans un prototype de fontion void fonct(tTableau param); param est
transformé en char *.
Et dans la définition de la fonction ?



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



Décidément pas beau, mais bon.
En fait, c'est lors de la simplification de mon code que j'ai écrit ca,

dans la version originale c'était plutot:
#define MAX_IDE 80
typedef char tcMonTypeAmoi[MAX_TYPE_A_MOI+1];

char **a_afficher;
Une variable globale, ce n'est pas joli non plus.

La, j'avais pas le choix. Je suis obligé

de passer par la fonction Afficher(void),
qui n'acceptant pas de paramètre,
je ne peux pas lui passer la fonction en paramètre

[coupé]


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



t est un pointeur vers char et Appele prend un pointeur vers un pointeur
vers char. L'adresse du premier élément de t est transmise successivement
dans Appele et dans Afficher, mais une fois rendu dans cette dernière, lors
du déréférencement (*a_afficher), c'est un caractère et pas une chaine de
caractères que tu obtiens. Ca peut planter (chez moi ca plante), et là il
s'agit d'un comportement indéfini (car %s attend une chaine terminée par
'').
La je suis d'accotrd que l'appel "fonctionne" plante.

Ma question est plutot, dans la version originale,
avec les tableaux, pourquoi l'appel "en panne"
plantait et l'appel "fonctionne" fonctionnait.


Avatar
Horst Kraemer
On Wed, 05 May 2004 15:59:12 +0200, Xavier Combelle
wrote:

D'après ce que j'ai compris,
le type tTableau est équivalent à un char *.
Ah non, tTableau est un type tableau, de même que pour tTableau t; t est est

un tableau.
Donc ca doit être en faisant cette supposition que je me suis giourré

C'est un peu plus complexe :
dans un prototype de fontion void fonct(tTableau param); param est
transformé en char *.
Et dans la définition de la fonction ?



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



Décidément pas beau, mais bon.
En fait, c'est lors de la simplification de mon code que j'ai écrit ca,

dans la version originale c'était plutot:
#define MAX_IDE 80
typedef char tcMonTypeAmoi[MAX_TYPE_A_MOI+1];

char **a_afficher;
Une variable globale, ce n'est pas joli non plus.

La, j'avais pas le choix. Je suis obligé

de passer par la fonction Afficher(void),
qui n'acceptant pas de paramètre,
je ne peux pas lui passer la fonction en paramètre

[coupé]


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



t est un pointeur vers char et Appele prend un pointeur vers un pointeur
vers char. L'adresse du premier élément de t est transmise successivement
dans Appele et dans Afficher, mais une fois rendu dans cette dernière, lors
du déréférencement (*a_afficher), c'est un caractère et pas une chaine de
caractères que tu obtiens. Ca peut planter (chez moi ca plante), et là il
s'agit d'un comportement indéfini (car %s attend une chaine terminée par
'').
La je suis d'accotrd que l'appel "fonctionne" plante.

Ma question est plutot, dans la version originale,
avec les tableaux, pourquoi l'appel "en panne"
plantait et l'appel "fonctionne" fonctionnait.


En principe il s'agit de la différence entre:

void f(tTableau t)
{
printf("%s",t)
et
printf("%s",&t)

}


ou bien entre

void f(char* p)
{
printf("%s",p)
et
printf("%s",&p)


Dans le premier cas tu passes à printf un pointeur de char. Dans le
deuxième cas tu passes à printf un pointeur vers un pointeur de char.
c.a.d. &p pointe vers de la mémoire qui contient la valeur du pointeur
p, c.a.d printf interprète les bytes qui représentent l'adresse d'une
chaine de caractères comme une chaine de caractères.

(le paramètre 't' ou 'p' de la fonction se comporte comme une variable
locale de la fonction).

--
Horst



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

Ca veut dire quoi UB?


Unspecified Behavior (comportement non spécifié par le standard, c.a.d.


Undefined...

--
-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
Regis TROADEC
Dans l'article , "Emmanuel

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

Ca veut dire quoi UB?


Unspecified Behavior (comportement non spécifié par le standard, c.a.d.


Undefined...


Tu n'as pas tout cité.

C'est si strict que ça ? UB = Undefined Behavior, pourquoi pas également
Unspecified Behavior ? Cet acronyme largement usité fait peut-être
référence le plus souvent à un comportement indéfini, à l'usage,
mais je n'ai jamais rien vu disant explicement que UB signifait
uniquement Undefined Behavior.

De plus, que ce soit un comportement non spécifié ou non défini par le
standard, les deux sont à proscrire. Tu peux me dire où tu as trouvé que
UB faisait uniquement référence à Undefined Behavior ?

Regis



Avatar
Xavier Combelle
Avec beaucoup de retard,

Merci à tous pour vos réponses.
1 2