web-dev-qa-db-ja.com

Cで参照渡し

関数が渡されたパラメーターの値を変更できるように、Cで参照渡しを使用しようとしています。これは関数のシグネチャです。

int locate(char *name, int &s, int &i)

ただし、コンパイルしようとすると、上記の行を具体的に参照する次のエラーが発生します。

エラー:「&」トークンの前に「;」、「、」、または「)」が必要です

'&'を削除すると、プログラムはコンパイルされますが、明らかに正しく機能しません。ここで何が問題になっていますか?参考図書で電話をかけるにはどうすればよいですか?

17
neuromancer

Cには参照がありません。変更する変数へのポインターを渡す必要があります。

int locate(char *name, int *s, int *i)
{
    /* ... */

    *s = 123;
    *i = 456;
}

int s = 0;
int i = 0;
locate("GMan", &s, &i);

/* s & i have been modified */
37
GManNickG

Cには参照変数がありませんが、参照をデータへのconstポインターと見なすことができます。

データへのconstポインタをこのようにして、ポインタが他のデータを指すことはできないが、それが指すデータは変更できるようにします。

int  locate (char *name,  int  * const s, int * const i)
20
Ashish

Cは参照渡しをサポートしていません。記述された方法で実行したり、に変更したりするには、C++が必要です。

int locate(char *name, int *s, int *i)

そして、2番目と3番目のパラメーター変数へのポインターを渡します。

7
wallyk

与えられた以前の回答はコンテキストが欠落しているようであり、Cポインターがオーバーロードされるという特性に対処していません。 Cが「参照によって通過する」と主張することは完全に公正です。ポインタis参照も。ただし、より正式には、Cの「参照」は、シンボルのメモリアドレスを表すメカニズムです。

  • ポインタは、メモリ内の変数であり、その値はアドレスとして扱われます。
  • 参照は、単にメモリアドレスの値リテラルです。
  • C言語では、参照渡しが可能ですが、適切なコンテキストでのみ可能です。

コンテキストの分離は、署名の定義と署名の呼び出しです。

プリミティブ_int a = 0x22e8;_を検討し、他の場所で_int* b = &a;_を宣言します(関数についてはすぐに説明します)。

これをメモリ内で視覚化できます(この例ではエンディアンは重要ではないと仮定します)。

_...
0x00000200:        22e8        ; this is the variable for int a's literal value:
                               ; a == 0x000022e8
                               ; &a == 0x00000200
0x00000???:        9090        ; ... more code ...
0x00000400:        0200        ; this is pointer b pointing to a's address:
                               ; b == 0x00000200
                               ; *b == 0x000022e8
                               ; &b == 0x00000400
...
_

特別なトリックなしに、ポインターを任意のアドレスに割り当てることができるのは簡単です。ポインターは単なる変数ですが、Cではポインターが指しているアドレスを参照できます。ポインタをその値アドレスから「逆参照」して、代わりに、呼び出しコンテキスト中にポインタをそのポインタの基になる値として扱うことができます:while ( *b == a ) ...。 _b == &a_を簡単に呼び出すことができます。

これを関数呼び出しに適用する場合、参照による受け渡しを区別するために、関数(署名)定義と呼び出しのコンテキストを分離する必要があります。

_int* foo(int* blah, int nah) { .. }     // signature definition context:
                                        // These are parameters
... vs ...

b = foo( &a, 4);                        // invocation context:
                                        // These are arguments
_

関数のシグネチャを定義する際に、引数にアクセスするアドレスをコンパイラに通知していません。ランタイムはまだ認識していません。 void bar(int &blah) {...}を定義するのはナンセンスです。代わりに、逆参照されたポインター構文(「渡された引数はすべて、ポイントされたアドレスにロードされます」)を使用して、ランタイムが発生したときに目的の引数値を参照します。したがって、Cは引数を参照で渡すことができます。

関数シグネチャ定義と関数呼び出しの両方のコンテキストは、コンパイラがポインタのオーバーロードと参照をどのように見るか、およびランタイムが実際にそれらに対処する方法を変更します。

2
ToFue

Cではこれを行うことはできません。 cには参照がないため、代わりにポインターを使用できます。

1
Raymond

参照渡しメソッドを使用して関数呼び出しで使用されるパラメーターを変更する場合は、常に関数の仮引数としてポインターを使用します。

したがって、これを使用する代わりに

int locate(char *name, int &s, int &i)

使用する、

int locate(char *name, int *s, int *i)

この関数を呼び出すときは、

.......。

int a=5;
int d=10;
char c='A'; 
int result;

result=locate(&c, &a, &d);

私はすべてが今明らかになることを願っています、

値渡しまたは参照渡しのどちらが優れているかについての詳細は、このソースが初心者に適しています。

http://www.learnc.net/call-by-reference.php

楽しんで。

1
Instructor RSL

(私はしばらくの間Cを使用していますが、Cのいくつかの概念にはまだかなり慣れていません。私の知る限り、これに答えようとしています。間違っている場合は、遠慮なく訂正してください)

参照渡しと言うときは、アドレスを渡します。そうする場合は、アドレスを指すポインターを使用します。したがって、関数プロトタイプへのポインターを渡す必要がありますが、実行しているのはアドレスを直接渡すことです。

関数が試みるのは、ポインターの逆参照(&を使用)ですが、パラメーター 's'および 'i'へのポインターを逆参照することはありませんでした。

関数プロトタイプ/定義を行う正しい方法は次のとおりです。

int locate(char *name, int *s, int *i)

この関数を呼び出す必要がある場合は、main関数または呼び出し関数で以下の宣言を使用します

int locate(char *name, &s, &i)  
1
Benq