転送元:http : //blog.csdn.net/fjb2080/article/details/5623427
オリジナル記事、転載元を明記してください、ありがとうございます!
著者:林青、ブログ名:ドゥ・ジングが空飛びます
ブログのアドレス:http : //blog.csdn.net/fjb2080
実際、CまたはC ++の場合、最も難しい部分はポインターであると推定されます。ポインターは強力ですが、多くの人が携帯する場所でもあります。
いくつかの時間は、前の記事「書いたCの 配列とポインタ++類似点と相違点 」CおよびC ++のポインタのための予備的な説明をしたが。今回は、関数パラメーターとしてポインターを渡す問題について説明します。
多くの人はポインタの使用に慣れていますが、ポインタの性質を理解していないため、ポインタの問題に含まれることがよくあります。実際、ポインタの性質を理解すれば、ポインタの使用法は明確になります。
Cの初心者として、ポインターを関数パラメーターとして渡すという2つの古典的な問題によく遭遇します。ここでは、これら2つの問題をポインタの本質で説明しますので、今後どのようなポインタ問題が発生しても、このようにポインタを解析すれば解決できるかもしれません!
まず、最初の質問はこれです:
2つのパラメーターの値を交換する関数を記述します。
初心者はよく書く:
void exchange(int x、int y)
{
int p = x;
x = y;
y = p;
}
その後、次のように記述する必要があることを理解するための情報が見つかります。
void交換(int * x、int * y)
{
int * p = x;
* x = * y;
* y = * p;
}
2番目の問題は、メモリをポインタに割り当てる関数を記述することです。
初心者はこのように書くことがよくあります:
void my_malloc(void * p、int size)
{
p = malloc(sizeof(int)* size);
}
それから私は情報をチェックして、それがこのように書かれるべきであることを知っていました:
void my_malloc(void ** p、int size)
{
* p = malloc(sizeof(int)* size);
}
インターネット上ではそのような議論がたくさんあり、多くの人が多くの説明をしてきましたが、はっきりと長く記憶できるような発言をすることはできませんでした。この記事は、初心者のためにこのような問題を解決しようとするだけのものです。原則的な理解!
まず、変数と同様にポインタにもアドレスがあることを覚えておく必要 がありますが、変数の値は値として解釈され、ポインタの値はアドレスとして解釈されます。
以下で、コードを見てみましょう。
void main()
{
int x;
int * p;
}
この関数のメモリ構造を見てみましょう。
これは関数のスタック構造です。変数とポインタの両方が4バイトを占めることがわかります。さらに、それらを初期化していないため、変数xとポインターpの内容はランダムです。つまり、xの値は不確かです。pを操作すると、pが特定のメモリアドレスを指すことがあります。プログラムがクラッシュします。
実際、ポインタにもアドレス の概念があることを思い出し、多くの問題が解決されました。
次に、ポインターが関数パラメーターとして渡される状況を分析します。
コードが次のようになっている場合、何が表示されますか。
int main(int argc、char * argv [])
{
int * a = new int(10);
func(a);
0を返します。
}
最初に言うことはもちろんです:ポインターにもアドレスがあります。
2番目に言うことは、変数を関数パラメーターに渡すと、この変数がコピーされるということです。
2番目の点については、ボイド交換(int x、int y)関数がこれら2つの変数の値を交換する必要があることを理解したときに理解する必要があります。
たとえば、次のとおりです。
int a;
int b;
exchange(a、b);
aとbの値を交換することはできません。現時点で交換されたaとbは元のaとbの変数ではないため、コピーされるだけです。
これらの2つの概念を使用すると、ポインターを関数パラメーターとして渡す問題を理解するのは難しくありません。
まず、上記のコードのポインタとpポインタのメモリ構造を見てみましょう。
私たちは、見ている私たちが中に入るのfunc関数パラメータ、およびコピー機能ポインタが、二つのポインタの内容として、10で同じメモリへのポイントであることが、同じであるとき。
理解できない場合は、コードとテストで説明します。
- #include <stdio.h>
- void func(int * p)
- {
- printf("* p =%d / n"、* p);
- printf("&p =%p / n"、&p);
- }
- int main(int argc、 char * argv [])
- {
- int * a = 新しい int(10);
- printf("* a =%d / n"、* a);
- printf("&a =%p / n"、&a);
- func(a);
- 0を返します。
- }
コンパイル:g ++ -g -Wall test1.cpp
実行:./a.out
出力:
* a = 10
&a = 0xbfd4447c
* p = 10
&p = 0xbfd44460
出力が表示されます。aが指すアドレスの値は、pが指すアドレスの値と同じです。両方とも10です。ただし、ポインターaとpについては、それら自身のアドレスが異なるため、関数funcはポインターaをpにコピーします。これらの値は同じですが、アドレスが異なり、ポインターが異なります。
さらに進みましょう:
- #include <stdio.h>
- void func(int * p)
- {
- printf("* p =%d / n"、* p);
- printf("&p =%p / n"、&p);
- printf("&* p =%p / n"、& p);
- }
- int main(int argc、 char * argv [])
- {
- int * a = 新しい int(10);
- printf("* a =%d / n"、* a);
- printf("&a =%p / n"、&a);
- printf("&* a =%p / n"、& a);
- func(a);
- 0を返します。
- }
コンパイル出力:
* a = 10
&a = 0xbfe1c77c
&* a = 0x94b6008
* p = 10
&p = 0xbfe1c760
&* p = 0x94b6008
我々はさらに、ポインタのアドレス値がアドレスとポインタ値pポイントが同じであることを見ることができ、そして、印象を深めるために、上に示したのと同様に、0x94b6008あるこのチャートを見て 、その後、再びプログラムの出力を比較して、 前述の2つのポイントを体験して ください。1つ目のポイントは、ポインタにアドレスがあること です。もう1つのポイントは、関数のパラメーターが過去にコピーされていること です。
それでは、記事の冒頭で述べた2つの問題に戻りましょう。1つは交換問題です。
void交換(int * x、int * y)
{
int * p = x;
* x = * y;
* y = * p;
}
なぜこれを交換できるのですか?
int a = 2;
int b = 3;
交換(&a、&b);
アドレスaとbを交換関数に渡したとき、関数は2つのアドレスをコピーし、それらを2つのポインターxとyに割り当てました。これらの2つのポインターは変数aとbを指しています。それらのグラフは次のとおりです。
したがって、ポインターを逆参照すると、次のようになります。
int * p = x;
* x = * y;
* y = * p;
aとbの変数の値を操作するため、aとbの値を正常に交換しました。
2番目の質問を見てみましょう。
void my_malloc(void * p、int size)
{
p = malloc(sizeof(int)* size);
}
これが当てはまる場合:
int * a;
my_malloc(a、10);
なぜこれが失敗するのですか?
次に、分析させてください。
my_malloc(a、10);関数を呼び出し、関数がp = malloc(size);ステートメントまで実行されていない場合、状況は次のようになります。
aとpのポインターの値は同じで、どちらも不定アドレスを指していることがわかります。
この時点で、次のステートメントを実行します。
p = malloc(sizeof(int)* size);
このステートメントを2つの部分に分割しましょう。1つは、最初にmalloc(sizeof(int)* size)を実行し、次に割り当てステートメントを実行して、malloc(sizeof(int)* size)の戻り値をpに支払うことです。
最初のステップ:最初にmalloc(sizeof(int)* size);を実行します(ここでは、mallocによるメモリの割り当ての成功のみを考慮しています)。
ステップ2:以下に示すように、malloc(sizeof(int)* size)の実行の戻り値をpに支払います。
上の写真から、これがまだアドレスをaに割り当てることができない理由であることがわかります。
以下でこれを分析してみましょう:
void my_malloc(void ** p、int size)
{
* p = malloc(sizeof(int)* size);
}
int * a;
my_malloc(&a、10);
なぜあなたはこのように成功するのですか?
関数が実行されると
my_malloc(void ** p、int size);
しかし、それは実装されていません
* p = malloc(sizeof(int)* size);
ステートメント、そのメモリ構造図は次のとおりです。
実際、ここでは、2次元ポインターと1次元ポインターを変数として扱うことができ、それらにもアドレスがあります。説明が違うだけです。
変数:内部の値は数値です。
1次元ポインター:内部の値はアドレスであり、このアドレスの値は数値です。
2次元ポインター:内部の値はアドレスであり、このアドレスの値もアドレスです。
だから、私はpを説明するために写真を見ました:
pはアドレスであり、このアドレスは&aであり、これはポインターaのアドレス値であり、ポインターaのアドレスの値もアドレスであり、このアドレスは不明な場所を指します。理解は良くなります!
malloc(size)を実行した後の図は次のとおりです。
次に、割り当てステートメントを実行します。
* p = malloc(sizeof(int)* size);
その後、以下に示すように:
次に、ポインタを正常に割り当てるためにメモリを割り当てました。
この記事のPDFダウンロードアドレス:関数のパラメーターとして渡されるC ++ポインターの問題.pdf