Je suis nouveau à C et j'ai un doute.
Étant donné que les fonctions C créent des copies locales de ses arguments, je me demande pourquoi le code suivant fonctionne comme prévu:
void function(int array[]){
array[0] = 4;
array[1] = 5;
array[2] = 6;
}
int main(){
int array[] = {1,2,3};
function(array);
printf("%d %d %d",array[0],array[1],array[2]);
return 0;
}
La sortie ligne étant de 4 5 6.
Pourquoi cela fonctionne-t-il alors que ce qui suit ne fonctionne pas?
void function(int integer){
integer = 2;
}
int main(){
int integer = 1;
function(integer);
printf("%d",integer);
return 0;
}
La sortie est juste 1 dans ce cas.
Version courte: pourquoi les fonctions peuvent-elles modifier les valeurs de leurs variables parentes si elles sont passées sous forme de tableau?
Merci à tous!
Cela est dû au fait que les tableaux ont tendance à se désintégrer en pointeurs.
int a[] = { 1, 2, 3 };
int* p = a; // valid: p is now the address of a[0]
a = p; // NOT valid.
printf("a = %p\n", a);
printf("p = %p\n", p); // prints same address as a
a
et p
imprimeront la même valeur.
Contrairement à ce que d'autres ont dit, a
n'est pas pas un pointeur, il peut simplement se désintégrer en un. http://c-faq.com/aryptr/aryptrequiv.html
Dans votre premier function()
ce qui est transmis est l'adresse du premier élément du tableau, et le corps de la fonction en déréférence. En fait, le compilateur traite le prototype de fonction comme suit:
void function(int* array /*you wrote int array[]*/){
array[0] = 4;
array[1] = 5;
array[2] = 6;
}
function(&array[0]);
Cela doit arriver parce que vous avez dit "tableau de taille inconnue" (int array []). Le compilateur ne pouvait pas garantir de déduire la quantité de pile requise pour passer par valeur, il se désintègre donc en un pointeur.
---- Modifier ----
Permet de combiner vos deux exemples et d'utiliser des noms plus distinctifs pour rendre les choses plus claires.
#include <stdio.h>
void func1(int dynArray[]) {
printf("func1: dynArray = %p, &dynArray[0] = %p, dynArray[0] = %d\n",
dynArray, &dynArray[0], dynArray[0]);
}
void func2(int* intPtr) {
printf("func2: intPtr = %p, &intPtr[0] = %p, intPtr[0] = %d\n",
intPtr, &intPtr[0], intPtr[0]);
}
void func3(int intVal) {
printf("func3: intVal = %d, &intValue = %p\n",
intVal, &intVal);
}
int main() {
int mainArray[3] = { 1, 2, 3 };
int mainInt = 10;
printf("mainArray = %p, &mainArray[0] = %p, mainArray[0] = %d\n",
mainArray, &mainArray, mainArray[0]);
func1(mainArray);
func2(mainArray);
printf("mainInt = %d, &mainInt = %p\n",
mainInt, &mainInt);
func3(mainInt);
return 0;
}
Démo en direct sur ideone: http://ideone.com/P8C1f4
mainArray = 0xbf806ad4, &mainArray[0] = 0xbf806ad4, mainArray[0] = 1
func1: dynArray = 0xbf806ad4, &dynArray[0] = 0xbf806ad4, dynArray[0] = 1
func2: intPtr = 0xbf806ad4, &intPtr[0] = 0xbf806ad4, intPtr[0] = 1
mainInt = 10, &mainInt = 0xbf806acc
func3: intVal = 10, &intValue = 0xbf806ad0
Dans func1
Et func2
"DynArray" et "intPtr" sont des variables locales, mais ce sont des variables de pointeur dans lesquelles ils reçoivent l'adresse de "mainArray" de main.
Ce comportement est spécifique aux tableaux. Si vous deviez placer le tableau dans une structure, vous seriez en mesure de le transmettre par valeur.
n tableau passé à une fonction est converti en un pointeur. Lorsque vous passez un pointeur comme argument à une fonction, vous donnez simplement l'adresse de la variable dans la mémoire. Ainsi, lorsque vous modifiez la valeur de la cellule du tableau, vous modifiez la valeur sous l'adresse donnée à la fonction.
Lorsque vous passez un entier simple à une fonction, l'entier est copié dans la pile, lorsque vous modifiez l'entier dans la fonction, vous modifiez la copie de l'entier, pas l'original.
En C, nous pouvons utiliser trois types de mémoire:
Dans le cas de ce tableau passé par une fonction, qui est un pointeur (adresse vers une autre variable), il est stocké dans la pile, lorsque nous appelons la fonction, nous copions le pointeur dans la pile.
Dans le cas de l'entier, il est également stocké dans la pile, lorsque nous appelons la fonction, nous copions l'entier.
Si nous voulons modifier l'entier, nous pouvons passer l'adresse de l'entier pour modifier la valeur sous le pointeur, comme ceci:
void function(int *integer)
{
*integer = 2;
}
int main()
{
int integer = 1;
function(&integer);
printf("%d", integer);
return 0;
}
Il y a une différence entre "passer par référence" et "passer par valeur"
Le passage par référence mène à un emplacement dans la mémoire où le passage par valeur passe directement la valeur, une variable de tableau est toujours une référence, donc elle pointe vers un emplacement dans la mémoire. Les entiers passeront par valeur par défaut
Dans le premier code, vous transmettez l'adresse du tableau pointant vers l'élément supérieur du tableau. Ainsi, lorsque vous modifiez la valeur dans la fonction et revenez à la fonction principale, vous accédez toujours au même tableau qui se trouve à la même adresse. Cela s'appelle passer par référence.
Cependant, dans le second cas, la valeur de l'entier est copiée de la fonction principale vers la fonction appelée. En d'autres termes, les deux entiers sont dans une adresse différente dans la mémoire. Donc, modifier l'un ne modifie pas l'autre.
Le nom du tableau est un pointeur sur le premier élément du tableau. Dans le premier exemple de code, vous avez passé un pointeur vers l'emplacement de mémoire contenant le premier élément du tableau. Dans le deuxième exemple de code, vous avez passé un entier par valeur, il n'a donc rien à voir avec la variable locale nommée "entier"
vérifier ce lien
Passer par référence et passer par valeur