tableaux 2d ...question de madame bellepaire de loche

tableaux 2d ...question de madame bellepaire de loche - C - Programmation

Marsh Posté le 24-10-2005 à 18:00:01    

bonjour,
 
1 - je voudrais savoir si on peut créer une fonction qui retourne un tableau à deux dimensions, sans utiliser de pointeurs. Si oui, comment-qu'on fait  :heink:  ?
 
2 - pourquoi si une fonction est :

Code :
  1. int ** mafonction(int chiffre);


 
je peux pas l'appeler par :

Code :
  1. int mon_tablo[7][7] = mafonction(7);


 
 
plus précisement, pourkoi, mais ô pourquoi ? mais pourquoi .. on peut pas déclarer un tableaux 2d pour une fonction qui renvoie un pointeurs 2d ???
 
merci par avance  :love:  :love:  :love:  :love:  :love:

Message cité 1 fois
Message édité par in_your_phion le 24-10-2005 à 18:02:09
Reply

Marsh Posté le 24-10-2005 à 18:00:01   

Reply

Marsh Posté le 24-10-2005 à 18:42:58    

Parce que le compilateur ne pourrait pas traduire l'instruction

**mafonction[j][i] = x;

car il ne connait pas le nombre de colonnes par ligne. Alors que s'il le savait, il pourrait traduire cela en *(mafonction + (j * col_max + i)(sizeof(int))) = x.

Message cité 1 fois
Message édité par olivthill le 24-10-2005 à 18:44:33
Reply

Marsh Posté le 24-10-2005 à 19:56:28    

olivthill a écrit :

Parce que le compilateur ne pourrait pas traduire l'instruction

**mafonction[j][i] = x;

car il ne connait pas le nombre de colonnes par ligne. Alors que s'il le savait, il pourrait traduire cela en *(mafonction + (j * col_max + i)(sizeof(int))) = x.


 
ben ok. Merci bien. Et pour ma première question  :whistle: ?

Reply

Marsh Posté le 24-10-2005 à 20:43:14    

in_your_phion a écrit :

ben ok. Merci bien. Et pour ma première question  :whistle: ?


 
Olivthill y a répondu.

Reply

Marsh Posté le 24-10-2005 à 21:11:05    

Elmoricq a écrit :

Olivthill y a répondu.


 
c'est pas très explicite ..la 2 j'ai compris, mais je voulais savoir si je peux faire un return d'un tableau 2d. Apparement pas possible mais je vois pas pourquoi ca a un lien avec la 2..


Message édité par in_your_phion le 24-10-2005 à 21:12:42
Reply

Marsh Posté le 25-10-2005 à 01:27:00    

Citation :

1 - je voudrais savoir si on peut créer une fonction qui retourne un tableau à deux dimensions, sans utiliser de pointeurs. Si oui, comment-qu'on fait  :heink:  ?


Désolé, je ne comprends pas bien la question, car de même que Monsieur Jourdain fait de la prose sans le savoir, de même l'informaticien utilise des pointeurs sans le savoir quand il manipule des tableaux.
 

Citation :

2 - pourquoi si une fonction est :  
Code :
int ** mafonction(int chiffre);
 
je peux pas l'appeler par :  
 
Code :
int mon_tablo[7][7] = mafonction(7);


int **mafonction(7) désigne un pointeur sur un pointeur, ce qui n'est pas la même chose que mon_tablo[7][7] qui est une valeur d'un tableau.
 
Quand on regarde le code assembleur généré par la déclaration de int mon_tableau[10][10], on voit qu'un espace continu pour 100 entiers est réservé, et que l'adresse du début est "mon_tableau". Cela revient au même que si l'on avait un tableau à une seule dimension, et il n'y a pas de notion de pointeur sur un pointeur ici.
 
 
 

Reply

Marsh Posté le 26-10-2005 à 11:39:03    

un tableau n'est pas une l-value, on ne peut pas ecrire  
int tab[2][3];
tab = qqchose;


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 26-10-2005 à 17:50:43    

Citation :


Désolé, je ne comprends pas bien la question, car de même que Monsieur Jourdain fait de la prose sans le savoir, de même l'informaticien utilise des pointeurs sans le savoir quand il manipule des tableaux.


 
ben .. ma question est peut on avoir une fonction qui fait return A; ou A est un tableau, et ou le type retourné n'est pas A** ou  A*, une sorte de A[] par exemple ? Par ailleurs, je croyais que les tableaux n'étaient pas des pointeurs, puisqu'ils ont une adresse fixe, nan ?
 

Citation :

Quand on regarde le code assembleur généré par la déclaration de int mon_tableau[10][10], on voit qu'un espace continu pour 100 entiers est réservé, et que l'adresse du début est "mon_tableau". Cela revient au même que si l'on avait un tableau à une seule dimension, et il n'y a pas de notion de pointeur sur un pointeur ici.


 
est ce que quand on fait un malloc les blocs mémoires alloués sont contigus ?
 
 :love: merci encore  :love:

Message cité 2 fois
Message édité par in_your_phion le 26-10-2005 à 17:50:59
Reply

Marsh Posté le 26-10-2005 à 18:56:31    

in_your_phion a écrit :


ben .. ma question est peut on avoir une fonction qui fait return A; ou A est un tableau, et ou le type retourné n'est pas A** ou  A*, une sorte de A[] par exemple ? Par ailleurs, je croyais que les tableaux n'étaient pas des pointeurs, puisqu'ils ont une adresse fixe, nan ?


que ce soit dans n'importe quel langage, un tableau est une suite de valeurs. or, ces valeurs sont stockées en mémoire, forcément. donc, l'adresse de départ d'un tableau (son pointeur)  est égale à l'adresse de son premier élément.
 

in_your_phion a écrit :


est ce que quand on fait un malloc les blocs mémoires alloués sont contigus ?


oui


Message édité par Harkonnen le 26-10-2005 à 18:59:51

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 26-10-2005 à 19:01:53    

Il me semble que la solution "Relis ton K&R" ferait pas de mal ...


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
Reply

Marsh Posté le 26-10-2005 à 19:01:53   

Reply

Marsh Posté le 27-10-2005 à 12:09:34    

0x90, il me semble que la solution est de rester calme et de ne pas envoyer promener les pauvres débutants, mêm s'ils se chosissent des pseudonymes qui sont presque des insultes.
 
Cher in_your_phion, ta question peut être divisiée en trois parties :
 
1. Quelles sont les données retournées par une fonction ?
2. Comment manipuler des tableaux à plusieurs dimensions ?
3. Quelle est la différence entre les crochets et les étoiles ?
 
Je ne répondrais qu'à la première maintenant, parce que je ne veux pas être trop long, parce que c'est celle qui me parait la plus importante, et parce que c'est celle qui me semble la moins souvent expliquée.
 
Dans le cas habituel d'une application Windows (32-bit), l'instruction return retourne quatre octets
L'instruction return ne peut pas retourner plus ou moins que ces 4 octets là. Elle ne peut pas retourner un tableau entier, ni même une chaine de caractères.
 
Puisque l'instruction return ne retourne que 4 octets, comment faire pour retourner un tableau ?
 
La solution est de retourner un pointeur sur un tableau. Mais, attention, ce tableau n'est pas créé par le return. Il est créé au préalable.
 
Il existe trois moyens pour créer un tableau:
 
1. Une déclaration (int mon_tableau[10][10];) au niveau global (en dehors d'une fonction).
2. Une déclaration (int mon_tableau[10][10];) au niveau local (dans une fonction).
3. Un appel à malloc(), GlobalAlloc() ou d'autres fonctions similaires.
 
Dans le premier et le troisème cas, le tableau est défini sur le "tas".
Dans le deuxième cas, le tableau est défini sur la "pile".
 
Une erreur de débutant très classique est la suivante :
 
int *ma_function()
{
   int tableau[3] = {1, 2, 3};
   return tableau;
}
 
Le pointeur sur le tableau va bien être retourné, mais le problème est que le tableau est défini sur la pile, et que lorsque le programme sort de la pile, le pointeur de pile est décrémenté, et ce qui se trouve au-dessus (le tableau) va être écrasé (sploutch) dés que le programme entrera dans une nouvelle fonction. Le débutant ne fait pas attention au fait que la durée de vie des éléments locaux est temporaire, et non pas permanente.
 
Il faut donc qu'une fonction retourne soit un entier, soit un pointeur vers une donnée allouée sur le tas et non pas allouée sur la pile de la fonction.
 
Mais, pour suivre les principes de la programmation modulaire structurée, et pour faciliter la lisibilité et la maintenance des programmes, le programmeur expérimenté n'écrit que jamais d'autres fonctions que celles qui retournent des entiers (qui sont des codes d'erreurs et de bon achèvement), et non pas celles qui retournent des pointeurs. S'il faut qu'une fonction modifie une chaine de caractère ou un tableau (cas très courant), cette chaine de caractère ou ce tableau est préalablement créé dans la fonction appelante, ou au niveau global, et est passé via un pointeur en argument de la fonction.
 
En résumé, quand une fonction a des données in (en lecture), et des données out (en modification), le débutant peut pesner qu'il faut passer les données in dans les paramètres, et avoir la donnée out dans le return, alors qu'en fait, il faut passer les données in et out en paramètres, et ne se servir du return que pour un code d'erreur ou de succès, même s'il est théoriquement possible de retourner un pointeur au lieu d'un code d'erreur ou de succès.
 
Il reste les deux autres questions à expliquer pour une prochaine fois si tu insistes beaucoup, et si tu ne trouves pas de réponse dans K & R (B. W. Kernigham et D. M. Ritchie).
 
 

Reply

Marsh Posté le 27-10-2005 à 15:04:39    

salut olivthill,
 

olivthill a écrit :

0x90, il me semble que la solution est de rester calme et de ne pas envoyer promener les pauvres débutants, mêm s'ils se chosissent des pseudonymes qui sont presque des insultes.


 
loin de moi cette idée .. je ne le repétrai jamais assez : in_your_phion est la concatenation de "in your philosophy, once-over". Ca me parait pourtant logique, il ne faut pas avoir l'esprit tordu ..   :ange:  
 

olivthill a écrit :


Cher in_your_phion, ta question peut être divisiée en trois parties :
 
1. Quelles sont les données retournées par une fonction ?
2. Comment manipuler des tableaux à plusieurs dimensions ?
3. Quelle est la différence entre les crochets et les étoiles ?
 
Je ne répondrais qu'à la première maintenant, parce que je ne veux pas être trop long, parce que c'est celle qui me parait la plus importante, et parce que c'est celle qui me semble la moins souvent expliquée.
 
Dans le cas habituel d'une application Windows (32-bit), l'instruction return retourne quatre octets
L'instruction return ne peut pas retourner plus ou moins que ces 4 octets là. Elle ne peut pas retourner un tableau entier, ni même une chaine de caractères.
 
Puisque l'instruction return ne retourne que 4 octets, comment faire pour retourner un tableau ?
 
La solution est de retourner un pointeur sur un tableau. Mais, attention, ce tableau n'est pas créé par le return. Il est créé au préalable.
 
Il existe trois moyens pour créer un tableau:
 
1. Une déclaration (int mon_tableau[10][10];) au niveau global (en dehors d'une fonction).
2. Une déclaration (int mon_tableau[10][10];) au niveau local (dans une fonction).
3. Un appel à malloc(), GlobalAlloc() ou d'autres fonctions similaires.
 
Dans le premier et le troisème cas, le tableau est défini sur le "tas".
Dans le deuxième cas, le tableau est défini sur la "pile".
 
Une erreur de débutant très classique est la suivante :
 
int *ma_function()
{
   int tableau[3] = {1, 2, 3};
   return tableau;
}
 
Le pointeur sur le tableau va bien être retourné, mais le problème est que le tableau est défini sur la pile, et que lorsque le programme sort de la pile, le pointeur de pile est décrémenté, et ce qui se trouve au-dessus (le tableau) va être écrasé (sploutch) dés que le programme entrera dans une nouvelle fonction. Le débutant ne fait pas attention au fait que la durée de vie des éléments locaux est temporaire, et non pas permanente.
 
Il faut donc qu'une fonction retourne soit un entier, soit un pointeur vers une donnée allouée sur le tas et non pas allouée sur la pile de la fonction.
 
Mais, pour suivre les principes de la programmation modulaire structurée, et pour faciliter la lisibilité et la maintenance des programmes, le programmeur expérimenté n'écrit que jamais d'autres fonctions que celles qui retournent des entiers (qui sont des codes d'erreurs et de bon achèvement), et non pas celles qui retournent des pointeurs. S'il faut qu'une fonction modifie une chaine de caractère ou un tableau (cas très courant), cette chaine de caractère ou ce tableau est préalablement créé dans la fonction appelante, ou au niveau global, et est passé via un pointeur en argument de la fonction.
 
En résumé, quand une fonction a des données in (en lecture), et des données out (en modification), le débutant peut pesner qu'il faut passer les données in dans les paramètres, et avoir la donnée out dans le return, alors qu'en fait, il faut passer les données in et out en paramètres, et ne se servir du return que pour un code d'erreur ou de succès, même s'il est théoriquement possible de retourner un pointeur au lieu d'un code d'erreur ou de succès.


 
 
d'accord. Mais si j'ai bien compris, on peut quand meme penser qu'il faut passer les données in dans les paramètres, et avoir la donnée out (dumoins son adresse de début) dans le return si la donnée out est écrite dans le tas ...... j'ai bon là ?
 
 

olivthill a écrit :


Il reste les deux autres questions à expliquer pour une prochaine fois si tu insistes beaucoup, et si tu ne trouves pas de réponse dans K & R (B. W. Kernigham et D. M. Ritchie).


 
I heavily and loudly insist sir ! j'insiste lourdement.. je veux savoir !!!!! please please please, it is a question de la plus haute importance sir, il en va de la protection de la reine votre honneur !
 
god save the queen, may you hear my request  :D
 
 
ps : pourquoi sizeof(void) vaut 1 et pas 4 ? peut on faire void* p = malloc(sizeof(void)) ?  :whistle:
 
 
 
 
 :love:  :love:  :love: merci encore  :love:   ;)   :love:

Message cité 2 fois
Message édité par in_your_phion le 27-10-2005 à 15:10:57
Reply

Marsh Posté le 27-10-2005 à 19:50:42    

C'etait pas méchant, le K&R raconte bien tout ca est est quand même assez clair sur le sujet il me semble, pourquoi aller chercher ailleurs? pourquoi ré-écrire ca pas en mieux bien sur un forum?
(void a aucune raison de valoir 4, c'est pas un pointeur , c'est void* qui vaut 4, pour peu qu'on reste en 32bits) (pour savoir si kkchose est faisable, fait le, compile avec tout les warnings, si ca gueule t'aura ta réponse)


Message édité par 0x90 le 27-10-2005 à 19:51:12

---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
Reply

Marsh Posté le 28-10-2005 à 09:52:50    

in_your_phion a écrit :

pourquoi sizeof(void) vaut 1 et pas 4 ? peut on faire void* p = malloc(sizeof(void)) ?  :whistle:


 
sur mon compilo sizeof(void) == 0 (vc++7.1)
que dit la norme a ce sujet ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 28-10-2005 à 11:08:15    

Bonne question pour la norme.
 
Mais j'aurais tendance à dire que "0" est le comportement attendu. :/

Reply

Marsh Posté le 28-10-2005 à 11:48:39    

Tiens, avec dev-c++/mingw, sizeof(void) = 1, j'aurais cru que c'était zéro.
 
Pour le reste, je conseille de se reporter au livre (de philosophie) de K & R, qui effectivement expliquera beaucoup mieux que moi que *toto est parfois équivalent à toto[], mais que **toto est très différent de toto[][], et de faire plein d'essais avec des programmes rééls.

Reply

Marsh Posté le 28-10-2005 à 12:49:46    

Si je dis pas de connerie, le void a été créé pour remplacer historiquement le char qu'on utilisait a la base, il a du hériter au passage de la taille du char... 'fin de toute facon, ca n'a pas de sens de demander la taille du void, on va pas allouer un void...


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
Reply

Marsh Posté le 31-10-2005 à 01:31:03    

in_your_phion a écrit :

1 - je voudrais savoir si on peut créer une fonction qui retourne un tableau à deux dimensions, sans utiliser de pointeurs.


Non. Ou alors il faut définir une structure incluant le tableau. C'est pas efficace, mais c'est simple.


Message édité par Emmanuel Delahaye le 31-10-2005 à 01:37:49

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 31-10-2005 à 01:33:34    

in_your_phion a écrit :

est ce que quand on fait un malloc les blocs mémoires alloués sont contigus ?


Pas clair. Si on fait UN malloc(), on alloue UN bloc. Dans ce bloc, la mémoire de ce bloc est contiguë.
Par contre, si on alloue N blocs, ces blocs ne sont pas contigus.


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 31-10-2005 à 01:37:01    

in_your_phion a écrit :

ps : pourquoi sizeof(void) vaut 1 et pas 4 ? peut on faire void* p = malloc(sizeof(void)) ?


En C standard. sizeof (void) n'est pas défini. (void est un type 'incomplet').
 
Si il vaut 1 sur ton compilateur, c'est que tu utilises un mode non standard (extension). Ce code n'est pas portable.


Message édité par Emmanuel Delahaye le 31-10-2005 à 01:38:29

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed