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

tableau souple

15 réponses
Avatar
PIGUET Bruno
Bonjour,

Pour créer, puis parcourir, un tableau constant (au sens du langage C),
mais pouvant évoluer (au fil des différentes versions), sans m'embêter
avec des #define NB_VAL ou autre, j'utilise un idiome basé sur sizeof
(tab) / sizeof (*tab) (voir l'ECM en PS).

Les avisés lecteurs de ce newsgroup ont-il un avis sur cette
technique ? Y-a-t'il un danger caché ? Avez-vous autre chose à
recommander ?.

Merci d'avance,

Bruno.

PS : voici l'ECM :

#include<stdio.h>

int
main ()
{
char *villes[] = { "Paris", "Lyon", "Toulouse" };
int i;

for (i = 0; i < sizeof (villes) / sizeof (*villes); i++)
{
printf ("%d : %s\n", i, villes[i]);
}
return 0;
}

10 réponses

1 2
Avatar
espie
In article <hq3v1q$uu$,
PIGUET Bruno wrote:
Bonjour,

Pour créer, puis parcourir, un tableau constant (au sens du langage C),
mais pouvant évoluer (au fil des différentes versions), sans m'embêter
avec des #define NB_VAL ou autre, j'utilise un idiome basé sur sizeof
(tab) / sizeof (*tab) (voir l'ECM en PS).

Les avisés lecteurs de ce newsgroup ont-il un avis sur cette
technique ? Y-a-t'il un danger caché ? Avez-vous autre chose à
recommander ?.



Il y a un danger pas trop bien cache: le jour ou tu passes a malloc
pour ton tableau, ca ne marche plus.
Avatar
PIGUET Bruno
Le Wed, 14 Apr 2010 08:50:20 +0000, Marc Espie a écrit :

Il y a un danger pas trop bien cache: le jour ou tu passes a malloc pour
ton tableau, ca ne marche plus.



Je n'envisage pas de passer à malloc() dans ce cas : c'est vraiment
pour un tableau constant codé en dur dans le code, mais dont le nombre
d'éléments peut changer d'une version à l'autre.
Ce n'est pas pour une fonction de bibliothèque, qui ne pourrait
effectivement pas faire d'hypothèse sur l'origine du tableau.

Bruno.
Avatar
FX
PIGUET Bruno a écrit :
Bonjour,

Pour créer, puis parcourir, un tableau constant (au sens du langage C),
mais pouvant évoluer (au fil des différentes versions), sans m'embêter
avec des #define NB_VAL ou autre, j'utilise un idiome basé sur sizeof
(tab) / sizeof (*tab) (voir l'ECM en PS).

Les avisés lecteurs de ce newsgroup ont-il un avis sur cette
technique ? Y-a-t'il un danger caché ? Avez-vous autre chose à
recommander ?.



N'oublie pas de mettre les sizeof entre parenthèses.
Avatar
PIGUET Bruno
Le Wed, 14 Apr 2010 12:07:24 +0200, FX a écrit :

N'oublie pas de mettre les sizeof entre parenthèses.



Ah, tiens ?
Pourquoi ?

En général, j'entoure de parenthèse les macros qui risquent de produire
quelque chose comme : a-b. Avec les parenthèses, le compilateur comprend
bien : (a1-b1)/(a2-b2) et pas : a1 - b1/a2 -b2.

Mais sizeof() n'est pas un macro, que je sache ?

Bruno.
Avatar
Antoine Leca
FX écrivit :
PIGUET Bruno a écrit :
sur sizeof (tab) / sizeof (*tab) (voir l'ECM en PS).



N'oublie pas de mettre les sizeof entre parenthèses.



Peut-on avoir plus de détails sur la position des parenthèses
supplémentaires que tu proposes et la raison de ta recommandation ?

Surtout que même si je comprend tout-à-fait la position de Bruno de
mettre des parenthèses en réalité inutiles mais qui évitent de se poser
des questions, j'ai l'habitude d'écrire le contraire :
sizeof tab / sizeof*tab

Et je ne vois pas de raison de mettre un appel de fonction ou un
indiçage (genre 2[villes]) derrière une expression comme celle-ci.


Antoine
Avatar
Éric Lévénez
Le 14/04/10 12:50, Antoine Leca a écrit :
FX écrivit :
PIGUET Bruno a écrit :
sur sizeof (tab) / sizeof (*tab) (voir l'ECM en PS).



N'oublie pas de mettre les sizeof entre parenthèses.



Peut-on avoir plus de détails sur la position des parenthèses
supplémentaires que tu proposes et la raison de ta recommandation ?

Surtout que même si je comprend tout-à-fait la position de Bruno de
mettre des parenthèses en réalité inutiles mais qui évitent de se poser
des questions, j'ai l'habitude d'écrire le contraire :
sizeof tab / sizeof*tab



Moi j'écris :

i < (int)(sizeof tab / sizeof *tab)

car comme le sizeof est non signé, je préfère masquer le warning du
compilateur. Mais tout cela ne marche que si la taille tient dans un int
signé.

--
Éric Lévénez
FAQ de fclc : <http://www.levenez.com/lang/c/faq/&gt;
Avatar
PIGUET Bruno
Le Wed, 14 Apr 2010 12:59:23 +0200, Éric Lévénez a écrit :


Moi j'écris :

i < (int)(sizeof tab / sizeof *tab)

car comme le sizeof est non signé, je préfère masquer le warning du
compilateur. Mais tout cela ne marche que si la taille tient dans un int
signé.



En fait, moi je penche plutôt pour définir i comme un size_t.

Mais alors, pour le printf, le format n'est plus %d, et on doit choisir
entre %lu (ce qui marche "en général", pour compilos C89) et %zd (en C99).
J'évite la solution passe-partout mais lourdingue :
écrire toujours %lu et en castant le size_t en unsigned long :
printf("%lu", (unsigned long) i);

Bruno.
Avatar
PIGUET Bruno
Le Wed, 14 Apr 2010 13:44:01 +0200, FX a écrit :


Je pensais aux parenthès qui englobent les 2 sizeof:

#define NUM_ELEM(tab) ( sizeof(tab) / sizeof(*tab) )
^ ^



Ah, OK, si je définis une macro qui englobe les sizeof.
effectivement, là, il vaut mieux.
Mais alors, pour la légèreté de la chose, on peut arriver à (cf message
d'Antoine) :

#define NUM_ELEM(tab) (sizeof tab / sizeof *tab)

J'ai vu parfois aussi, pour ceux qui préfèrent les notations tableaux aux
pointeurs :

#define NUM_ELEM(tab) (sizeof tab / sizeof tab[0])

Bruno.
Avatar
espie
In article <4bc5a00b$0$10469$,
à ric Lévénez wrote:
Le 14/04/10 12:50, Antoine Leca a écrit :
FX écrivit :
PIGUET Bruno a écrit :
sur sizeof (tab) / sizeof (*tab) (voir l'ECM en PS).



N'oublie pas de mettre les sizeof entre parenthèses.



Peut-on avoir plus de détails sur la position des parenthèses
supplémentaires que tu proposes et la raison de ta recommandation ?

Surtout que même si je comprend tout-à-fait la position de Bruno de
mettre des parenthèses en réalité inutiles mais qui évitent de se poser
des questions, j'ai l'habitude d'écrire le contraire :
sizeof tab / sizeof*tab



Moi j'écris :

i < (int)(sizeof tab / sizeof *tab)

car comme le sizeof est non signé, je préfère masquer le warning du
compilateur. Mais tout cela ne marche que si la taille tient dans un int
signé.



Ca serait mieux que le compilo ne fasse pas chier et apprenne a reconnaitre
ce genre d'idiomes et ne pas donner d'avertissements inutiles.

Je suis de moins en moins fan des cast "pour faire joli", surtout qu'un
jour, on change du code, et hop, le gentil cast se transforme en
pointer -> int ou autre joyeusete.

C'est tres dommage que C n'ait pas importe un equivalent des casts modernes
de C++. Meme si on peut ne pas aimer la syntaxe, c'est une vraie bonne
idee...
Avatar
zwim
Le Wed, 14 Apr 2010 08:40:26 +0000 (UTC)
PIGUET Bruno a écrit
Bonjour,

Pour créer, puis parcourir, un tableau constant (au sens du langage C),
mais pouvant évoluer (au fil des différentes versions), sans m'embêter
avec des #define NB_VAL ou autre, j'utilise un idiome basé sur sizeof
(tab) / sizeof (*tab) (voir l'ECM en PS).

Les avisés lecteurs de ce newsgroup ont-il un avis sur cette
technique ? Y-a-t'il un danger caché ? Avez-vous autre chose à
recommander ?.

Merci d'avance,

Bruno.

PS : voici l'ECM :

#include<stdio.h>

int
main ()
{
char *villes[] = { "Paris", "Lyon", "Toulouse" };
int i;

for (i = 0; i < sizeof (villes) / sizeof (*villes); i++)
{
printf ("%d : %sn", i, villes[i]);
}
return 0;
}



Pour changer un peu le fil de la discussion, il y a aussi possibilité
de faire comme avec les chaines de caractères des tableaux AZT (à zéro
terminal) et ainsi s'affranchir du nombre d'éléments.

La valeur terminale dépendra des données, par exemple -1 pour un
tableau de nbr positifs, NULL, "", ou tout autre valeur qu'on puisse
différentier des valeurs potentiellement utilies.

#include<stdio.h>

int main (void)
{
char *villes[] = { "Paris", "Lyon", "Toulouse", NULL };
int i;

for (i = 0; villes[i]; i++)
{
printf ("%d : %sn", i, villes[i]);
}

return 0;
}

--
zwim.
Rien n'est impossible que la mesure de la volonté humaine...
1 2