[C] pointeurs et passage de paramètres
Fermé
nadsky
Messages postés
162
Date d'inscription
mardi 3 juillet 2007
Statut
Membre
Dernière intervention
11 décembre 2011
-
20 juil. 2007 à 09:39
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 20 juil. 2007 à 10:02
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 20 juil. 2007 à 10:02
A voir également:
- [C] pointeurs et passage de paramètres
- Ouvrir paramètres - Guide
- Passage qwerty azerty - Guide
- Paramètres de confidentialité - Guide
- Paramètres dns - Guide
- Parametres comptes options de connexion - Guide
2 réponses
Utilisateur anonyme
20 juil. 2007 à 09:46
20 juil. 2007 à 09:46
on met &min,&max car dans la fonction, les valeur de min vont changer. si tu passe par par ardresses, lors de la sortie de la fonction, les valeurs changés reprendront leur valeur qe'elles avaien avant de rentrer dans la fonction.
exemple:
min=5:
max=3;
statut=minMaxTableau(monTableau,TAILLE,min,max); //on met dans cette fonction min à 10 et max à 20
printf("%d %d\n",min,max);//ca va donner 5 et 3
exemple 2:
min=5:
max=3;
statut=minMaxTableau(monTableau,TAILLE,&min,&max); //on met dans cette fonction min à 10 et max à 20
printf("%d %d\n",min,max);//ca va donner 10 et 20
voila :D
exemple:
min=5:
max=3;
statut=minMaxTableau(monTableau,TAILLE,min,max); //on met dans cette fonction min à 10 et max à 20
printf("%d %d\n",min,max);//ca va donner 5 et 3
exemple 2:
min=5:
max=3;
statut=minMaxTableau(monTableau,TAILLE,&min,&max); //on met dans cette fonction min à 10 et max à 20
printf("%d %d\n",min,max);//ca va donner 10 et 20
voila :D
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
20 juil. 2007 à 10:02
20 juil. 2007 à 10:02
Les appels de fonction en C
En C tout paramètre est en fait une recopie des variables d'appel. Exemple
... ne fait rien car le x du main est recopié lors de l'appel d'incrémenter, et la fonction incrémente cette recopie. Quand on revient dans le main, le x du main n'a pas bougé. La seule façon de modifier x, c'est de passer son adresse (concrètement on recopie son adresse, mais cette adresse px est bien celle de x : ainsi *px permet bien de modifier la valeur de x depuis incrémenter) :
En C++ c'est plus simple on utilise directement des références, mais ce n'est pas le sujet du jour.
Rappels sur les pointeurs
J'insiste sur le fait qu'un pointeur est TOUJOURS une adresse et fait donc TOUJOURS la même taille en mémoire. Le type d'un pointeur n'a aucune importance sauf en terme de warning c'est toujours une adresse. Le type d'une adresse générique est "void *", et l'adresse d'un plop est de type "plop *". On peut bien sur manipuler des pointeurs sur des adresses (par exemple un char ** est l'adresse d'un char * qui est l'adresse d'un char).
Pour récupérer l'adresse d'un objet plop on utilise l'opérateur & :
Pour récupérer l'objet (où la référence en C++) se trouvant à une adresse px, on utilise l'opérateur *:
Une segmentation fault revient à évaluer le contenu d'une adresse invalide, c'est à dire qui désigne une zone qui n'a pas été allouée par ton programme (par exemple si tu as oublié de faire un malloc, et que ton pointeur n'a pas été initialisé avec une adresse valide comme par exemple l'adresse d'une variable de ton programme).
L'opérateur [] du C ne fait qu'utiliser l'opérateur * en se décalant de i cases (c'est d'ailleurs pour ca que quand i est hors du tableau ca fait une erreur de segmentation), c'est juste une façon simplifiée d'écrire les choses. C'est également pour cette raison qu'un tableau d'int est un "int *", par exemple tab[0] (ie *tab) est bien de type int.
Chercher le min et le max d'un tableau
Ici min et max doivent être modifiés par notre fonction, on doit donc passer leur adresse. On a besoin du tableau, mais aussi de sa taille, car le pointeur du tableau comme on vient de le voir ne donne que la position de sa première case en mémoire. Comme on veut s'arrêter au bout de ce tableau, il faut bien passer une information permettant de le détecter. Ici on choisit le nombre de case, mais ca aurait pu être l'adresse de la dernière case. Si un jour tu fais du C++ tu verras que c'est plus ou moins ce que font les iterators. Bref dans notre cas ça donne :
Ce qui donne
Bonne chance
En C tout paramètre est en fait une recopie des variables d'appel. Exemple
#include <stdio.h> void incrementer(int x){ ++x; } int main(){ int x =2; incrementer(x); return 0; }
... ne fait rien car le x du main est recopié lors de l'appel d'incrémenter, et la fonction incrémente cette recopie. Quand on revient dans le main, le x du main n'a pas bougé. La seule façon de modifier x, c'est de passer son adresse (concrètement on recopie son adresse, mais cette adresse px est bien celle de x : ainsi *px permet bien de modifier la valeur de x depuis incrémenter) :
void incrementer2(int *px){ ++(*px); }
En C++ c'est plus simple on utilise directement des références, mais ce n'est pas le sujet du jour.
Rappels sur les pointeurs
J'insiste sur le fait qu'un pointeur est TOUJOURS une adresse et fait donc TOUJOURS la même taille en mémoire. Le type d'un pointeur n'a aucune importance sauf en terme de warning c'est toujours une adresse. Le type d'une adresse générique est "void *", et l'adresse d'un plop est de type "plop *". On peut bien sur manipuler des pointeurs sur des adresses (par exemple un char ** est l'adresse d'un char * qui est l'adresse d'un char).
Pour récupérer l'adresse d'un objet plop on utilise l'opérateur & :
plop p; plop *px = &p;
Pour récupérer l'objet (où la référence en C++) se trouvant à une adresse px, on utilise l'opérateur *:
plop *px = (plop *) malloc(sizeof(plop)); plop p = *px;
Une segmentation fault revient à évaluer le contenu d'une adresse invalide, c'est à dire qui désigne une zone qui n'a pas été allouée par ton programme (par exemple si tu as oublié de faire un malloc, et que ton pointeur n'a pas été initialisé avec une adresse valide comme par exemple l'adresse d'une variable de ton programme).
L'opérateur [] du C ne fait qu'utiliser l'opérateur * en se décalant de i cases (c'est d'ailleurs pour ca que quand i est hors du tableau ca fait une erreur de segmentation), c'est juste une façon simplifiée d'écrire les choses. C'est également pour cette raison qu'un tableau d'int est un "int *", par exemple tab[0] (ie *tab) est bien de type int.
Chercher le min et le max d'un tableau
Ici min et max doivent être modifiés par notre fonction, on doit donc passer leur adresse. On a besoin du tableau, mais aussi de sa taille, car le pointeur du tableau comme on vient de le voir ne donne que la position de sa première case en mémoire. Comme on veut s'arrêter au bout de ce tableau, il faut bien passer une information permettant de le détecter. Ici on choisit le nombre de case, mais ca aurait pu être l'adresse de la dernière case. Si un jour tu fais du C++ tu verras que c'est plus ou moins ce que font les iterators. Bref dans notre cas ça donne :
#include <stdio.h> #include <stdlib.h> void minmax(int *tab,unsigned taille,int *min,int *max){ unsigned i; *min = tab[0]; *max = tab[0]; for(i=0;i<taille;++i){ *min = tab[i] < *min ? tab[i] : *min; *max = tab[i] > *max ? tab[i] : *max; } } int main(){ int min,max; unsigned i; const unsigned taille = 5; int *tab = (int *) calloc(taille,sizeof(int)); // je mets des valeurs au pif dans le tableau for(i=0;i<taille;++i){ tab[i] = (i-2)*i; printf("tab[%i] = %d\n",i,tab[i]); } minmax(tab,taille,&min,&max); printf("min = %d max = %d\n",min,max); free(tab); return 0; }
Ce qui donne
(mando@aldur) (~) $ gcc -W -Wall plop.c (mando@aldur) (~) $ ./a.out tab[0] = 0 tab[1] = -1 tab[2] = 0 tab[3] = 3 tab[4] = 8 min = -1 max = 8
Bonne chance