[C] pointeurs et passage de paramètres
bonjour,je suis en train de relire mes tp de 1ere année et,n'étant pas très douée surtout avec les pointeurs,je rencontre quelques difficultés de compréhension.
en effet le but du tp est de chercher le minimum et la maximum dans un tableau avec des entiers tirés aléatoirement dans[0,50]
dans le main,on crée un tableau d'entiers,dont la taille est spécifiée dans le #define,puis trois variables de travail:min,max et statut de type entier.
voici les prototypage de fonction:
void initialisationGenerateur();
void remplirTableau(int leTableau[],int nombreElements);
void afficherTableau(int leTableau[],int nombreElements);
int minMaxTableau( int leTableau[], int nombreElements, int*rangMinimum, int*rangMaximum);
les trois premières fonctions font intervenir une "copie" des variables(si j'ai bien compris),alors que la dernière intervient directement sur les adresses de variables grace aux pointeurs.
cependant,toujours dans le main,lorsqu'on recherche le maximum et le minimum,on a la ligne suivante:
statut=minMaxTableau(monTableau,TAILLE,&min,&max);
si je comprends,on met & du fait qu'on passe les adresses des variables min et max à cette fonction minMaxTableau,mais je ne comprends pas pourquoi on ne passe pas les adresses des autres paramètres pour cette fonction(celle du tableau monTableau entre autres)pour pouvoir travailler directement dessus au lieu d'en faire une copie...(j'ai d'ailleurs vu qu'il était laborieux de copier tout un tableau)
voila,j'espère que j'ai été assez claire...merci d'avance
voici la définition de la fonction minMaxTableau:
int minMaxTableau(int tab[],int nb,int *ptMin, int*ptMax)
{
int i;
if(nb==0)
return -1;
*ptMin=*ptMax=0;
for(i=1;i<nb;i++)
if(tab[i]< tab[*ptMin])
*ptMin=i;
if(tab[i]> tab[*ptMax])
*ptMax=i;
}
return 0;
}
en effet le but du tp est de chercher le minimum et la maximum dans un tableau avec des entiers tirés aléatoirement dans[0,50]
dans le main,on crée un tableau d'entiers,dont la taille est spécifiée dans le #define,puis trois variables de travail:min,max et statut de type entier.
voici les prototypage de fonction:
void initialisationGenerateur();
void remplirTableau(int leTableau[],int nombreElements);
void afficherTableau(int leTableau[],int nombreElements);
int minMaxTableau( int leTableau[], int nombreElements, int*rangMinimum, int*rangMaximum);
les trois premières fonctions font intervenir une "copie" des variables(si j'ai bien compris),alors que la dernière intervient directement sur les adresses de variables grace aux pointeurs.
cependant,toujours dans le main,lorsqu'on recherche le maximum et le minimum,on a la ligne suivante:
statut=minMaxTableau(monTableau,TAILLE,&min,&max);
si je comprends,on met & du fait qu'on passe les adresses des variables min et max à cette fonction minMaxTableau,mais je ne comprends pas pourquoi on ne passe pas les adresses des autres paramètres pour cette fonction(celle du tableau monTableau entre autres)pour pouvoir travailler directement dessus au lieu d'en faire une copie...(j'ai d'ailleurs vu qu'il était laborieux de copier tout un tableau)
voila,j'espère que j'ai été assez claire...merci d'avance
voici la définition de la fonction minMaxTableau:
int minMaxTableau(int tab[],int nb,int *ptMin, int*ptMax)
{
int i;
if(nb==0)
return -1;
*ptMin=*ptMax=0;
for(i=1;i<nb;i++)
if(tab[i]< tab[*ptMin])
*ptMin=i;
if(tab[i]> tab[*ptMax])
*ptMax=i;
}
return 0;
}
A voir également:
- [C] pointeurs et passage de paramètres
- Parametres de mon ordinateur - Guide
- Passage qwerty azerty - Guide
- Paramètres dns - Guide
- Paramètres de confidentialité - Guide
- Le bon coin mon compte parametres - Guide
2 réponses
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
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