Question

Dans le programme C ci-dessous, je ne comprends pas pourquoi buf [0] = 'A' après que je l'appelle foo. Est-ce pas foo faire passe par la valeur?

#include <stdio.h>
#include <stdlib.h>

    void foo(char buf[])
    {
      buf[0] = 'A';
    }

    int main(int argc, char *argv[])
    {
      char buf[10];

      buf[0] = 'B';
      printf("before foo | buf[0] = %c\n", buf[0]);
      foo(buf);
      printf("after foo | buf[0] = %c\n", buf[0]);

      system("PAUSE"); 
      return 0;
      }

sortie:

before foo | buf[0] = 'B' 
after foo | buf[0] = 'A'
Était-ce utile?

La solution

void foo(char buf[])

est le même que

void foo(char* buf)

Lorsque vous appelez, foo(buf), vous passez un pointeur en valeur, donc une copie du pointeur est faite.

Une copie du pointeur pointe vers le même objet que le pointeur d'origine (ou, dans ce cas, à l'élément initial de la matrice).

C ne doit pas passer par la sémantique de référence dans le sens que C ++ a passer par la sémantique de référence. Tout en C est passé par valeur. Les pointeurs sont utilisés pour obtenir passe par la sémantique de référence.

Autres conseils

un tableau est juste une façon élégante d'utiliser un pointeur. Lorsque vous passez buf à la fonction, vous passez pointeur par la valeur, mais quand vous déréférencer le pointeur, vous toujours référence à la chaîne il pointe.

tableau comme paramètre de fonction est équivalente à un pointeur, de sorte que la déclaration

void foo( char buf[] );

est le même que

void foo( char* buf );

L'argument de la matrice est alors cariées pour le pointeur vers le premier élément.

Les tableaux sont traités différemment des autres types; vous ne pouvez pas passer un tableau « en valeur » dans C

norme en ligne C99 (projet n1256) , la section 6.3.2.1, "lvalues, les tableaux et les désignateurs de fonction", paragraphe 3:

  

Sauf quand il est l'opérande de l'opérateur sizeof ou unaire & opérateur, ou est   chaîne littérale utilisée pour initialiser un tableau, une expression qui a le type « « tableau de type » » est   converti en une expression de type « « pointeur de type » » qui pointe vers l'élément initial de   l'objet de réseau et n'a pas une lvalue. Si l'objet de tableau a enregistrer la classe de stockage, la   comportement est indéfini.

Dans l'appel

foo(buf);

l'expression matrice buf ne l'opérande de sizeof ou &, ni une chaîne littérale étant utilisée pour initialiser un tableau, il est donc implicitement converti ( « désintégrations ») de type « réseau 10-élément de char » à « pointeur vers un char », et adresse du premier élément est passé à foo. Par conséquent, tout ce que vous faites à buf dans foo() sera reflétée dans le tableau de buf dans main(). En raison de la façon dont subscripting de tableau est défini, vous pouvez utiliser un opérateur sur un type indice de pointeur pour le faire regarde comme vous travaillez avec un type de tableau, mais vous n'êtes pas.

Dans le cadre d'une déclaration de paramètre de fonction, T a[] et T a[N] sont synonymes de T *a, mais cela est uniquement cas où cela est vrai.

* omble buf [] signifie réellement char ** vous passez par pointeur si / référence. Cela vous donne que buf est un pointeur, aussi bien dans la fonction principale () et foo ().

Parce que vous passez un pointeur vers buf (en valeur). Ainsi, le contenu étant pointé par buf est modifiée.

Avec des pointeurs, il est différent; vous passez par valeur, mais ce que vous êtes de passage est la valeur du pointeur, ce qui est la même que la valeur du tableau.

Ainsi, la valeur du pointeur ne change pas, mais vous modifiez ce qu'il pointe vers.

tableaux et pointeurs sont (presque) la même chose.

int* foo = malloc(...)

foo[2] est le même que *(foo+2*sizeof(int))

anecdote: vous avez écrit

int main(int argc, char *argv[])

il est légal aussi (compilera et travailler le même) pour écrire

int main(int argc, char **argv)

et aussi

int main(int argc, char argv[][])

ils sont effectivement les mêmes. son un peu plus compliqué que cela, car un tableau sait combien d'éléments il a, et un pointeur ne fonctionne pas. mais ils sont utilisés les mêmes.

afin de passer que par la valeur, la fonction aurait besoin de connaître la taille de l'argument. Dans ce cas, vous êtes juste de passage d'un pointeur.

Vous passez ici par référence. Dans cet exemple, vous pouvez résoudre le problème en passant un seul omble chevalier à l'index du tableau souhaité.

Si vous souhaitez conserver le contenu du tableau d'origine, vous pouvez copier la chaîne de stockage temporaire dans la fonction.

edit: Que se passerait-il si vous enveloppé votre tableau de caractères dans une structure et passé le struct? Je crois que cela pourrait fonctionner, même si je ne sais pas quel genre de frais généraux qui pourraient créer au niveau du compilateur.

S'il vous plaît noter une chose,

Déclaration

void foo(char buf[])

dit, qui utilisera la notation []. Non quel élément de tableau que vous utiliserez.

si vous souhaitez signaler que, vous voulez obtenir une valeur spécifique, vous devez déclarer cette fonction comme

void foo(char buf[X]); //where X would be a constant.

Bien sûr, il est impossible, car il serait inutile (fonction pour fonctionner à l'élément n-ième du tableau?). Vous ne devez pas d'écrire des informations qui élément du tableau que vous voulez obtenir. Tout ce que vous avez besoin est simple déclaration:

voi foo(char value);

...

void foo(char buf[])

est une déclaration qui dit que la notation que vous voulez utiliser ([] - partie), et il contient également pointeur sur des données

.

De plus ... qu'est-ce que vous attendez ... vous avez envoyé à la fonction foo un nom du tableau

foo(buf);

qui est équivalent à & buf [0]. Alors ... c'est un pointeur.

Arrays en C ne sont pas passés par valeur. Ils ne sont même pas des paramètres de fonction légitimes. Au lieu de cela, le compilateur voit que vous essayez de passer un tableau et à pointeur rétrograde. Elle le fait en silence parce qu'il est mal. Il aime aussi lancer des chiots.

Utilisation des tableaux dans les paramètres de fonction est une belle façon de signaler à vos utilisateurs de l'API que cette chose devrait être un bloc de mémoire segmentée en morceaux de taille n octets, mais ne vous attendez pas compilateurs pour prendre soin si vous épelez char *foo char foo[] ou char foo[12] dans les paramètres de fonction. Ils ne vont pas.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top