Matrice et fonctions [Résolu] - C - Programmation
Marsh Posté le 09-01-2007 à 04:34:42
exhortae a écrit : Voilà je veux faire une fonction qui lit les élements d'une matrice mais le code suivant refuse de se compiler :
|
Bienvenue dans le monde des tableaux à plusieurs dimensions !!!
Le pb du débutant, c'est qu'il a tendance à croire que [] <=> * donc [][] <=> **
L'équivalence n'est vrai que pour une seule dimension. Pourquoi ? parce que la mémoire n'est définie, en mémoire, que sur une seule dimension. Les cases mémoires sont alignées sur une seule et immense ligne.
Donc le code suivant
void init(int tab[], int max) |
Peut être sans problème remplacé par
void init(int *tab, int max) |
Avec le main unique
int main() |
Avec 2 dim, ce n'est plus du tout vrai. Parce que, pour un tableau de 5 lignes sur 10 colonnes, style "int t[5][10]", lorsque tu fais "t[i][j]", le compilo remplace par "la case située à i * 10 + j". Il en ressort que si tu passes "t" à une fonction, il faut que la fonction connaisse quand-même la largeur du tableau pour pouvoir calculer la position de ses cases.
Donc le code suivant
void init(int tab[5][10], int lig, col) |
Peut être sans problème remplacé par
void init(int *tab[10], int lig, col) |
Mais ne peut absolument pas être remplacé par
void init(int **tab, int lig, col) |
Car là, dans la fonction "init", le compilo ne connait pas la largeur du tableau et ne peut donc pas calculer la position de l'élément demandé.
Le main, lui, reste unique
int main() |
En fait, l'équivalence [] <=> * ne marche que pour la première dimension du tableau. Et dès qu'on travaille en plusieurs dim, t'es obligé de conserver les autres.
exhortae a écrit : en essayant de le corriger, j'arrive à ça :
|
C'est le pire danger qui pouvait t'arriver: En ligne 3 tu déclares "a" un tableau de 10 pointeurs. Puis, sur ces pointeurs qui pointent on ne sais-où, tu vas y remplir des trucs. Mais tu ne sais absolument pas si tu ne pointes pas sur des zones allouées à d'autres variables (il n'y a qu'une mémoire). Le résultat te donne un comportement indéfini, c'est à dire où tout peut arriver (j'aime bien cette définition donnée par Emmanuel Delahaye), y compris que cela fonctionne parce que, par chance, tu tapes dans des zones libres. Puis, un jour, tu rajoutes un peu de code banal, style un autre tableau, un printf(), une fonction, un truc totalmeent bateau et là ça plante. Et évidement tu chercheras la cause du plantage dans les quelques lignes que t'auras rajouté alors qu'elle sera en ligne 3.
Pour éviter ce danger, il faut toujours se rappeler d'un truc très simple: quand tu as un pointeur style "int *t", tu n'as pas le droit d'aller taper dans "t[i]" (qui est aussi "*(t + i)" ) si t'as pas écrit avant "t=<qqchose>". Ca peut être n'importe quoi mais faut que ce soit valide. Evidemment les deux seuls trucs qu'on peut mettre dans "<qqchose>" sont
Exemples
int tablo[10]; |
int var; |
int *t; |
La règle est valable pour "n" dimensions. T'as pas le droit de taper dans "t[x][y][z]" si "t" ou t[x]" ou "t[x][y]" n'ont pas été alloués auparavant. Or toi, tu vas taper dans "a[i][j]" (équivalent à "*(*(a + i) + j)" ) alors que "a[i]" n'a pas été alloué !!!
exhortae a écrit : mais bon le problème c'est que j'aimerais une fonctions standard, et ne pas être obligé de spécifier [10 = nombre de colonne] |
Pas de miracle. Tu déclares "a" comme un pointeur sur un pointeur sur un int (int **a), puis tu alloues à "a" l'espace pour ranger "l" pointeurs sur des int (a=malloc(l * sizeof(int*))) puis tu fais une boucle de 0 à l et tu alloues à chaque "a[i]" l'espace pour ranger c int (a[i]=malloc(c * sizeof(int))).
Là, ce n'est plus un beau carré que tu as mais une pelote de laine où tu peux suivre chaque fil de façon indépendante. Tu pourras donc à loisir aller taper dans "a[i][j]". Le compilo partira de "a" pour aller "i" pointeurs plus loin (tous les éléments de "a" se suivent en mémoire). Ce pointeur ayant été rempli par le a[i]=malloc(...), le compilo pourra aller sur "*a[i]" (<=> a[i][0]) puis, de là, se déplacer sur la case "j" qui se trouve à "j * int" octets plus loin.
N'oublie pas en final, de refaire une boucle de 0 à l et de libérer les "a[i]" avec des "free()" puis, enfin, de libérer "a" par un "free()" final.
Marsh Posté le 09-01-2007 à 19:36:43
exhortae a écrit : Bonsoir
|
Mauvais type.
http://mapage.noos.fr/emdel/notes.htm#param_tab
Marsh Posté le 10-01-2007 à 15:29:31
Sve@r a écrit :
|
oui une erreur de précipitation, mais là c'est bon je sais que je dois y faire attention pour les fois prochaines
Sve@r a écrit :
|
là ça marche, mais moi ce que je voudrais c'est que ça soit la fonction qui se charge de faire le tout (allocation et saisie), j'ai donc essayer ça :
Code :
|
mais ça ne marche pas (je pense à cause d'une erreur dans le scanf de la fonction)
Marsh Posté le 10-01-2007 à 16:35:18
exhortae a écrit :
|
Tout à fait. Tu jongles remarquablement bien avec les pointeurs... mais tu as fait une minuscule erreur d'indirection probablement due à tous ces niveaux d'étoiles que tu manipules (au delà de "**" n'importe qui commence à avoir du mal)
C'est scanf("%d", &(*m)[i][j]) qu'il faut mettre, ou plus simplement scanf("%d", m[i][j]). Pourquoi ? Parce que "m" est déjà un pointeur. D'ailleurs, un simple raisonnement aurait dû te montrer ton erreur:
D'ailleurs t'as pensé à ce que j'avais suggéré au début, à savoir regrouper ton tableau et son nombre d'éléments dans une structure ? 1) ça te simplifierait la vie au niveau des paramètres que tu passes à "lire_tab" et 2) ça réduirait toutes tes jongleries avec les "***" et cie...
exhortae a écrit : mon prof n'était pas au courant de ça |
Ben change de prof parce que c'est quand-même une des bases du C !!!
Marsh Posté le 10-01-2007 à 17:17:11
Sve@r a écrit : D'ailleurs, un simple raisonnement aurait dû te montrer ton erreur:
|
jla prends comme méthode pour tester si ça va marcher à partir de maintenant
donc voilà j'ai suivi tes indications mais à l'exécution j'obtient l'erreur suivante :
voilà le code
Code :
|
Sve@r a écrit : |
si j'y ai pensé mais ma connaissance des structure actuellement me permet pas d'être à l'aise avec ça, même si ça a l'air facile je préfère appréhender les choses une par une (et en ce moment c'est les pointeurs )
Sve@r a écrit : |
pas possible de changer (pour l'instant)
Marsh Posté le 10-01-2007 à 22:11:20
exhortae a écrit : jla prends comme méthode pour tester si ça va marcher à partir de maintenant |
Ca marche à tous les coups
exhortae a écrit : donc voilà j'ai suivi tes indications mais à l'exécution j'obtient une erreur |
Oui, en écrivant le post précédent je me disais "est-ce qu'il ne va pas y avoir un pb ici" et finallement, il y a bien eu les pb auxquels je pensais.
1)
exhortae a écrit :
|
Pas bon. La priorité des opérateurs fait que le compilo commencera par faire "m[i]" c'est à dire aller à la case "i" puis faire "ce qui est pointé par cette case" c'est à dire n'importe quoi.
Toi, ce que tu veux, c'est aller d'abord au pointé de "m", c'est à dire "*m" puis aller à la case "i" à partir de ce pointé, c'est à dire
(*m)[i] = (int*) malloc (c * sizeof (int)); |
2)
exhortae a écrit :
|
Idem (mais là, c'est ma faute). Il faut commencer par faire "*m" pour aller au pointé, puis se déplacer à la case [i][j] puis demander l'adresse de cette case, c'est à dire
scanf ("%d", &((*m)[i][j])) |
Là j'ai testé.
Donc l'astuce que j'ai expliquée marche à tous les coups... à condition que les priorités soient bien de notre coté sinon dommage !!!
exhortae a écrit : si j'y ai pensé mais ma connaissance des structure actuellement me permet pas d'être à l'aise avec ça, même si ça a l'air facile je préfère appréhender les choses une par une (et en ce moment c'est les pointeurs ) |
Pas de pb - A chaque jour suffit sa peine...
Marsh Posté le 11-01-2007 à 18:35:50
Oui je me disais bien qu'il y avait un truc avec les parenthèses mais j'avais pas réussi à trouver, en tout cas les choses commencent à se mettre en place dans ma tête niveau pointeurs et fonctions, beaucoup grâce à toi, merci pour ton aide
Marsh Posté le 09-01-2007 à 00:18:53
Bonsoir
Voilà je veux faire une fonction qui lit les élements d'une matrice mais le code suivant refuse de se compiler :
et le problème je sais pas pourquoi .
en essayant de le corriger, j'arrive à ça :
ça à le mérite de fonctionner , mais bon le problème c'est que j'aimerais une fonctions standard, et ne pas être obligé de spécifier [10 = nombre de colonne], voilà si quelqu'un pouvait m'expliquer où est l'erreur ça serait sympa
merci
PS : je veux pas utiliser de fonction int** lire_tab (int l, int c) mais bien une fonction void
Message édité par exhortae le 11-01-2007 à 18:40:09