質問
は、以下のCプログラムでは、私はなぜBUF [0] = 'A' 私がfooを呼び出す後を理解していません。 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'
解決
void foo(char buf[])
は
と同じですvoid foo(char* buf)
あなたはそれを呼び出す、foo(buf)
は、あなたが値でポインタを渡し、そのポインタのコピーが作成されます。
元のポインタとして(または、この場合、配列の最初の要素へ)同じオブジェクトへのポインタポイントのコピー
Cは、C ++は参照セマンティクスを通過しているという意味で参照セマンティクスでパスを持っていません。 Cでのすべてが値によって渡されます。ポインタは参照セマンティクスでパスを取得するために使用されます。
他のヒント
の配列はポインタを使用するだけの空想の方法です。あなたが関数にbuf
を渡すときは、値によって、のポインタのを渡しているが、あなたはポインタを逆参照するとき、あなたはまだそれが指す文字列を参照しています。
関数のパラメータとして配列はポインタと同等であるので、宣言
void foo( char buf[] );
は
と同じですvoid foo( char* buf );
配列引数は、その最初の要素へのポインタにの減衰したのである
アレイは異なり、他のタイプよりも扱われます。あなたがCで「値によって」の配列を渡すことはできません。
オンラインC99標準(ドラフトn1256)>、セクション6.3.2.1、 "左辺値、配列、および機能指定子"、段落3:
それはのsizeof演算子のオペランドまたは単項&演算子であり、またはAである場合を除き、文字列リテラルは、アレイ、タイプ「『型の配列』を有する発現を初期化するために使用」であります の最初の要素を指していることを「型へのポインタ」型で表現に変換 配列オブジェクトと左辺値ではありません。配列オブジェクトは、ストレージ・クラスを登録している場合 動作は未定義である。
タグの呼び出しで
foo(buf);
アレイ発現buf
はsizeof
又は&
のオペランドはなく、またそれは暗黙的に変換されるので、(「減衰」)、アレイを初期化するために使用されている文字列リテラルであるタイプ「チャーの10要素アレイ」から最初の要素の「チャーへのポインタ」、およびアドレスがFOOに渡されます。そのため、あなたはbuf
でfoo()
に行うものがbuf
でmain()
配列に反映されます。配列の添字が定義されている方法のので、あなたはポインタ型に添字演算子を使用することができますので、のルックスのあなたは配列型で作業しているが、あなたはありませんしているよう。
関数のパラメータ宣言の文脈において、T a[]
とT a[N]
はT *a
と同義であるが、これはそれが本当であるのみの場合です。
* char型のbufは[]は、実際に**文字を意味します。 それは、(bufは、両方のメインの中で、ポインタであることをあなたに与えます)とFOO のの()関数ます。
あなたが(値により)buf
へのポインタを渡しているので。コンテンツはbuf
によって指されているように変更されます。
;あなたは値渡しますが、何を渡していることは、配列の値と同じではないポインタの値ですされます。
ですから、ポインタの値は変わりませんが、あなたはそれが指しているもの変更しています。
配列とポインタは、(ほぼ)同じものである。
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[][])
彼らが効果的に同じです。配列は、それが持っているどのように多くの要素を知っている、とポインタがないので、そのわずかに多く、それよりも複雑。しかし、彼らは同じように使用されます。
の値によってそれを渡すために、関数は、引数のサイズを知っておく必要があります。この場合、あなただけのポインタを渡しています。
あなたはここに参照渡しされています。この例では、所望の配列のインデックスに単一文字を渡すことによって、問題を解決することができます。
あなたは、元の配列の内容を保持したい場合は、は、関数内で一時保管に文字列をコピーすることができます。
編集:あなたは構造のあなたのchar配列を包み、構造体を通過した場合はどうなるでしょうか?私は、コンパイラレベルで作成する場合があり、そのオーバーヘッドの種類を知りませんがそれは、あまりにもうまくいくかもしれないと考えています。
一つのことに注意してください、
宣言
void foo(char buf[])
は、[]表記を使用すること、言います。ないその配列の要素は、使用されます。
あなたはいくつかの特定の値を取得したい、というポイントをご希望の場合、その後、あなたは
としてこの関数を宣言する必要がありますvoid foo(char buf[X]); //where X would be a constant.
それは無駄になるのではもちろん、それは、(アレイのn番目の要素で操作するための機能?)ことは不可能です。あなたが取得したい配列の要素の情報を書き留めする必要はありません。あなたが必要なものすべてがシンプルな宣言です:
voi foo(char value);
そう...
void foo(char buf[])
あなたが使用したい記法と言う宣言([] - 一部)であり、それはまた、いくつかのデータへのポインタが含まれています。
。また...あなたは何を期待...あなたは
関数fooに配列の名前を送りましたfoo(buf);
BUF [0]&に相当する。そう...これはポインタです。
Cにおける配列は値によって渡されません。彼らは合法的な関数のパラメータではありません。代わりに、コンパイラは、配列を渡ししようとしていることを見ていると、ポインタにそれを降格します。それは悪だからそれは黙ってこれを行います。また、子犬を蹴るのが好き。
関数のパラメータで配列を使用すると、このことは、メモリのブロックであることを、あなたのAPIユーザーへの信号に良い方法では、nバイトに分割チャンクをサイズの、しかし、あなたはchar *foo
char foo[]
またはchar foo[12]
を綴る場合のケアにコンパイラを期待していません関数のパラメータインチ彼らはしません。