Passer un tableau par référence en C

Je suis nouveau à C et j’ai un doute.

Puisque 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 de ligne étant 4 5 6.

Pourquoi cela fonctionne-t-il alors que les suivantes ne fonctionnent 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 parent si elles sont passées sous forme de tableau?

Merci à tous!

Cela est dû au fait que les tableaux ont tendance à se décomposer en indicateurs.

 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 afficheront la même valeur.

Contrairement à ce que d’autres ont dit, a n’est pas un pointeur, il peut simplement se désintégrer. http://c-faq.com/aryptr/aryptrequiv.html

Dans votre premier function() ce qui est passé est l’adresse du premier élément du tableau, et le corps de la fonction le supprime. Enfait, le compilateur traite le prototype de fonction comme ceci:

 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 tableau []). Le compilateur ne pouvait pas garantir la déduction de la quantité de stack nécessaire pour passer, il se désintègre donc en un pointeur.

—- Modifier —-

Combinons vos exemples et utilisons des noms plus distinctifs pour rendre les choses plus claires.

 #include  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 func1 , “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 placez le tableau dans une structure, vous pourrez le passer par valeur.

Un tableau passé à une fonction est converti en un pointeur . Lorsque vous passez un pointeur en tant qu’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 transmettez un entier simple à une fonction, l’entier est copié dans la stack. Lorsque vous modifiez l’entier dans la fonction, vous modifiez la copie de l’entier et non l’original.

Rappel des différents types de mémoire en C

En C, on peut utiliser trois types de mémoire:

  • la stack, utilisée pour les appels locaux de variables et de fonctions : lorsque nous créons une variable dans main (), nous utilisons la stack pour stocker la variable et, lorsqu’une fonction est appelée, les parameters donnés à la méthode sont enregistrés dans la stack. Lorsque nous quittons une fonction, nous “sautons” ces parameters pour revenir à l’état d’origine, avec la variable utilisée avant l’appel de la fonction. (anecdote: un stackoverflow, c’est quand on pirate la stack pour utiliser les variables précédentes dans une fonction sans la passer en paramètre)
  • le tas qui correspond à la mémoire allouée dynamicment : lorsque nous avons besoin de grandes quantités de données, nous utilisons ce tas car la stack est limitée à quelques mégaoctets.
  • le code où sont stockées les instructions du programme

Dans le cas où ce tableau est passé par une fonction, qui est un pointeur (adresse à une autre variable), il est stocké dans la stack. Lorsque nous appelons la fonction, nous copions le pointeur dans la stack.

Dans le cas de l’entier, il est également stocké dans la stack. 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’

Passer par référence conduit à un emplacement dans la mémoire où passer par valeur transmet directement la valeur, une variable de tableau étant toujours une référence, elle pointe donc vers un emplacement dans la mémoire. Les entiers passeront par valeur par défaut

Dans le premier code, vous passez l’adresse du tableau pointant vers le premier élément du tableau. Ainsi, lorsque vous modifiez la valeur dans la fonction et que vous revenez à la fonction principale, vous accédez toujours au même tableau qui se trouve à la même adresse. Ceci 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 sur l’emplacement de mémoire contenant le premier élément de tableau. Dans le deuxième exemple de code, vous avez passé un entier par sa valeur, ce qui 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

Passer par référence / valeur en C ++