6

以下のCプログラムでは、fooを呼び出した後にbuf [0]='A'である理由がわかりません。fooは値渡しをしていませんか?

#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;
      }

出力:

before foo | buf[0] = 'B' 
after foo | buf[0] = 'A'
4

12 に答える 12

12
void foo(char buf[])

と同じです

void foo(char* buf)

これを呼び出すと、foo(buf)ポインタを値で渡すため、ポインタのコピーが作成されます。

ポインタのコピーは、元のポインタと同じオブジェクト(またはこの場合は配列の最初の要素)を指します。

C ++には参照渡しのセマンティクスがあるという意味で、Cには参照渡しのセマンティクスがありません。Cのすべてが値によって渡されます。ポインタは、参照セマンティクスによるパスを取得するために使用されます。

于 2010-08-05T13:30:17.900 に答える
4

配列は、ポインタを使用するためのすばらしい方法です。buf関数に渡すときは、値でポインターを渡しますが、ポインターを逆参照するときは、それが指す文字列を参照していることになります。

于 2010-08-05T13:29:25.983 に答える
2

配列は他のタイプとは異なる方法で処理されます。Cでは「値で」配列を渡すことはできません。

オンラインC99標準(ドラフトn1256)、セクション6.3.2.1、「左辺値、配列、および関数指定子」、段落3:

sizeof演算子またはunary&演算子のオペランドである場合、または配列を初期化するために使用される文字列リテラルである場合を除き、「型の配列」型の式は、「ポインタ型」の型の式に変換されます。配列オブジェクトの最初の要素を指し、左辺値ではない''と入力します。配列オブジェクトにレジスタストレージクラスがある場合、動作は未定義です。

通話中

foo(buf);

配列式はまたbufはのオペランドではなく、配列の初期化に使用される文字列リテラルでもないため、「charの10要素配列」から「charへのポインタ」に暗黙的に変換(「減衰」)されます。そして、最初の要素のアドレスがfooに渡されます。したがって、で行うことはすべて、の配列に反映されます。配列の添え字がどのように定義されているかにより、ポインター型に添え字演算子を使用して、配列型を操作しているように見せることができますが、そうではありません。 sizeof&buffoo()bufmain()

関数パラメーター宣言のコンテキストでは、T a[]はとT a[N]同義T *aですが、これはそれが当てはまる場合 のみです。

于 2010-08-05T13:59:07.300 に答える
2

関数パラメーターとしての配列はポインターと同等であるため、宣言

void foo( char buf[] );

と同じです

void foo( char* buf );

次に、配列引数は最初の要素へのポインターに減衰されます。

于 2010-08-05T13:32:26.820 に答える
1

* char buf[]は実際にはchar**を意味するため、ポインター/参照を渡します。これにより、bufはmain()関数とfoo()関数の両方でポインターになります。

于 2010-08-05T13:28:29.620 に答える
1

buf(値で)へのポインタを渡しているからです。そのため、ポイントされているコンテンツbufが変更されます。

于 2010-08-05T13:29:20.587 に答える
1

ポインタの場合は異なります。値で渡しますが、渡すのはポインタの値であり、配列の値と同じではありません。

したがって、ポインタの値は変更されませんが、ポインタが指しているものを変更します。

于 2010-08-05T13:30:57.823 に答える
1

配列とポインタは(ほぼ)同じものです。

int* foo = malloc(...)

foo[2]と同じです*(foo+2*sizeof(int))

逸話:あなたは書いた

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

書くことも合法です(コンパイルして同じように動作します)

int main(int argc, char **argv)

そしてまた

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

それらは事実上同じです。配列は要素の数を認識しているのに対し、ポインターは認識していないため、それよりも少し複雑です。しかし、それらは同じように使用されます。

于 2010-08-05T17:29:48.520 に答える
0

Cの配列は値で渡されません。それらは正当な関数パラメーターでさえありません。代わりに、コンパイラーは、配列を渡そうとしていることを認識し、それをポインターに降格します。それは悪なので、これを静かに行います。子犬を蹴るのも好きです。

char *foo char foo[]関数パラメーターで配列を使用することは、これがnバイトサイズのチャンクにセグメント化されたメモリのブロックであることをAPIユーザーに通知するための優れた方法ですが、コンパイラーがスペルまたはchar foo[12]関数パラメーターで気にすることを期待しないでください。彼らはしません。

于 2010-08-05T13:58:56.777 に答える
0

それを値で渡すために、関数は引数のサイズを知る必要があります。この場合、ポインタを渡すだけです。

于 2010-08-05T13:29:59.617 に答える
0

ここでは参照により通過しています。この例では、目的の配列のインデックスに1つの文字を渡すことで問題を解決できます。

元の配列の内容を保持したい場合は、文字列を関数の一時ストレージにコピーできます。

編集:char配列を構造体でラップし、構造体を渡した場合はどうなりますか?コンパイラレベルでどのようなオーバーヘッドが発生するかはわかりませんが、それでもうまくいくと思います。

于 2010-08-05T13:36:12.053 に答える
0

1つのことに注意してください、

宣言

void foo(char buf[])

言う、それは[]表記を使用します。使用する配列の要素ではありません。

それを指摘したい場合は、特定の値を取得したい場合は、この関数を次のように宣言する必要があります。

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

もちろん、それは役に立たないので不可能です(配列のn番目の要素で動作するための関数?)。配列のどの要素を取得したいかという情報を書き留める必要はありません。必要なものはすべて単純な宣言です。

voi foo(char value);

それで...

void foo(char buf[])

は、使用する表記法([] --part)を示す宣言であり、一部のデータへのポインターも含まれています。

さらに...あなたは何を期待しますか...あなたは関数fooに配列の名前を送りました

foo(buf);

これは&buf[0]と同等です。だから...これはポインタです。

于 2010-08-05T13:52:11.190 に答える