C言語における伝達値と伝達ポインタ


C言語の伝値や伝針を聞いたことがあるかもしれませんが、他の言語でも伝引用がありますが、彼らにはいったいどんな違いがありますか.もしあなたがまだ正確に見分けられないなら、よく理解しなければなりません.
値を伝える
私たちはC言語を初めて勉強したときに先生に教えられたことがあります.次の方法ではaとbの値を交換することはできません.
#include
void swap(int a,int b)
{
    int temp = a;
    a = b;
    b = temp;
    printf("swap a = %d,b = %d
",a,b); } int main(void) { int a = 10; int b = 20; printf("before swap:a = %d,b = %d
",a,b); swap(a,b); printf("after swap:a = %d,b = %d
",a,b); return 0; }

実行結果は次のとおりです.
before swap:a = 10,b = 20                                                                                                                                                                   
internal swap a = 20,b = 10                                                                                                                                                                 
after  swap:a = 10,b = 20

aとbの値は最終的に交換されていないことがわかる.最初はa,bの値は10,20であったが,最終的には同じ値であった.
どうしてですか.関数パラメータは、伝達されるとき、いずれも元のデータのコピーであるため、すなわち、swap内部で使用されるaとbは、最も初期のaとbのコピーにすぎないため、swap関数内部でaとbを変更しても、初期のaとbの値には影響しない.
そのため,構造体を直接パラメータとしないで効率が低いことがしばしば知られている.構造体自体がバイト数を多く占めるため、パラメータとして直接使用すると、大きな「コピー」が生成され、効率が低下します.
次の図を組み合わせて理解します.
まず、図中のブロックの上部aおよびbはmain関数のaおよびb、すなわち元のデータを表し、ボックスの下部aおよびbは関数のパラメータaおよびb、すなわち元のデータの「コピー」を表す.(後の図はすべてこのようにして、上部は元の値を表して、下部は関数のパラメータの値を表します).
swap関数を呼び出す前後の状況は次のとおりです.
swapではaとbのコピーのみが操作されるため、元のaとbの値にはまったく影響しません.最終的にはaとbの値を交換する目的も達成できない.
ポインタ
では、上記の問題を解決するために、ポインタが必要であることを知っています.コードは次のとおりです.
#include
void swap(int *a,int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
    printf("swap a = %d,b = %d
",*a,*b); } int main(void) { int a = 10; int b = 20; printf("before swap:a = %d,b = %d
",a,b); swap(&a,&b); printf("after swap:a = %d,b = %d
",a,b); return 0; }

実行結果:
before swap:a = 10,b = 20                                                                                                                                                                   
swap a = 20,b = 10                                                                                                                                                                          
after  swap:a = 20,b = 10

この場合,a,bの値こそ真の交換であることがわかる.
どうしてまた伝値があって、また伝針があります
ここを見て、なぜ関数にパラメータを渡すとき、値を伝えるか、ポインタを伝えるか疑問に思っています.なぜポインタはパラメータの値を変えることができますか?実際、C言語では、パラメータ伝達はすべて値伝達です!つまり、あなたが考えているポインタも値ですが、その値はポインタタイプにすぎません.
図を通して、前のなぜポインタがa,bの値を交換できるのかを理解します.
図から分かるように、関数に渡されるのはaとbを指すポインタのコピーであるが、そのコピーも同様にaとbを指すため、ポインタの指向を変えることはできないが、パラメータaとbが指す内容、すなわち元のaとbの値を変えることができる.
ポインタを見て
ポインタpのためにメモリを申請する場合、次のコードは目的を達成できますか?
#include
#include
void getMemery(int *p)
{
    /*  1024 int  */
    p = malloc(sizeof(int)*1024);
    if(NULL == p)
    {
        printf("malloc failed
"); p = NULL; } } int main(void) { int *p = NULL; getMemery(p); printf("address of p is %p
",p); return 0; }

前の内容の分析では、予想された効果に達していないに違いない.
実行結果:
address of p is (nil)

これはなぜですか.また,getMemory関数に渡されるパラメータはいずれもコピーであるため,関数内のpも外部pのコピーであるため,関数内部で新しい申請のメモリにpを指し示しても,外部pの値,すなわちpがNULLを指し示すことはないということを,前述したように解析した.
どのように修正しますか?pのアドレス、すなわちintタイプのポインタを指すポインタが必要です.
#include
#include
void getMemery(int **p)
{
    /*  1024 int  */
    *p = malloc(sizeof(int)*1024);
    if(NULL == *p)
    {
        printf("malloc failed
"); *p = NULL; } } int main(void) { int *p = NULL; getMemery(&p); printf("address of p is %p
",p); free(p); p = NULL; return 0; }

実行結果は次のとおりです.
address of p is 0x144f010

実行結果からpの値が変更されたことがわかります.
次の図に合わせて理解できます.
まとめ
以下にまとめます.
  • 関数のパラメータはすべて元のデータの"コピー"であるため、関数内で元のデータ
  • を変更することはできない.
  • 関数のパラメータはいずれも伝値であり、伝針は本質的に伝値
  • である.
  • インバウンドコンテンツを変更するには、そのインバウンドのアドレス(ポインタも参照も同様の役割を果たす)を伝達する必要があり、その指向するコンテンツ
  • を逆参照により修正する.
  • 以上の結論はC言語
  • に限定されない.