C言語における伝達値と伝達ポインタ
C言語の伝値や伝針を聞いたことがあるかもしれませんが、他の言語でも伝引用がありますが、彼らにはいったいどんな違いがありますか.もしあなたがまだ正確に見分けられないなら、よく理解しなければなりません.
値を伝える
私たちはC言語を初めて勉強したときに先生に教えられたことがあります.次の方法ではaとbの値を交換することはできません.
実行結果は次のとおりです.
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の値を交換する目的も達成できない.
ポインタ
では、上記の問題を解決するために、ポインタが必要であることを知っています.コードは次のとおりです.
実行結果:
この場合,a,bの値こそ真の交換であることがわかる.
どうしてまた伝値があって、また伝針があります
ここを見て、なぜ関数にパラメータを渡すとき、値を伝えるか、ポインタを伝えるか疑問に思っています.なぜポインタはパラメータの値を変えることができますか?実際、C言語では、パラメータ伝達はすべて値伝達です!つまり、あなたが考えているポインタも値ですが、その値はポインタタイプにすぎません.
図を通して、前のなぜポインタがa,bの値を交換できるのかを理解します.
図から分かるように、関数に渡されるのはaとbを指すポインタのコピーであるが、そのコピーも同様にaとbを指すため、ポインタの指向を変えることはできないが、パラメータaとbが指す内容、すなわち元のaとbの値を変えることができる.
ポインタを見て
ポインタpのためにメモリを申請する場合、次のコードは目的を達成できますか?
前の内容の分析では、予想された効果に達していないに違いない.
実行結果:
これはなぜですか.また,getMemory関数に渡されるパラメータはいずれもコピーであるため,関数内のpも外部pのコピーであるため,関数内部で新しい申請のメモリにpを指し示しても,外部pの値,すなわちpがNULLを指し示すことはないということを,前述したように解析した.
どのように修正しますか?pのアドレス、すなわちintタイプのポインタを指すポインタが必要です.
実行結果は次のとおりです.
実行結果からpの値が変更されたことがわかります.
次の図に合わせて理解できます.
まとめ
以下にまとめます.関数のパラメータはすべて元のデータの"コピー"であるため、関数内で元のデータ を変更することはできない.関数のパラメータはいずれも伝値であり、伝針は本質的に伝値 である.インバウンドコンテンツを変更するには、そのインバウンドのアドレス(ポインタも参照も同様の役割を果たす)を伝達する必要があり、その指向するコンテンツ を逆参照により修正する.以上の結論は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の値が変更されたことがわかります.
次の図に合わせて理解できます.
まとめ
以下にまとめます.