C ++ポインタの詳細な説明(ターン)

 

1.ポインタを知る

ポインタとは何ですか?私たちの心の中のポインターがどのように見えるかを考えてください:

ここに画像の説明を挿入します
そのような?それでは、今日は「ポインタ」テーブルの使い方についてお話しましょう!

ここに画像の説明を挿入します
冗談ではありません!
プログラミング言語では、ポインタは上記の「ポインタ」よりもはるかに抽象的です。ですから、勉強するとき、ポインタのようなものがあることをよく知っていますが、混乱していて、使い方がわかりません。次に、ポインタとは何かを直感的に感じてもらいます!

簡単に言えば、ポインタは特別な種類の変数です。特別な点は、この変数は通常の値(1、2、100、 'q'など)を格納しないことです。0x101、0x886などのメモリアドレスを格納します。

理解していなくても構いません。以下に、ポインタが何であるかを誰もが直感的に理解できるように回路図を示します。
ここに画像の説明を挿入します
注:図の0x886は、想定される仮想アドレスを説明するためのものです。

変数のストレージがメモリスペースを占有することは誰もが知っています。
この図では、Ageは変数であり、そのストレージアドレスは0x886であり、その保存された値は18です。
pAgeはポインタであり、特別な変数とも言えます。そのストレージアドレスは0x601であり、その保存されたコンテンツは0x886です。

比較すると、ポインタと変数には多くの類似点があることが簡単にわかります。違いは、ポインタがメモリアドレスを格納することです。

よく見ると、次のことがわかります。ポインタpAgeに格納されているアドレス=変数Ageのメモリアドレス。したがって、ポインタpAgeはメモリユニットAgeを指す特殊変数とも言えます。

この時点で、誰もがポインタを直感的に理解していると思います。では、どのように使用するのでしょうか。
次の4つの部分をマスターすると、ポインターを簡単に使い始めることができます。

  1. ポインタを宣言する
  2. &を使用して変数アドレスを取得します
  3. ポインタを使用してアドレスを格納する
  4. *を使用してポイントされたデータにアクセスします

これらの4つの部分を別々に勉強しましょう!

(1)ポインタを宣言します

特別な変数として、ポインターも宣言する必要があります。最初に、[C ++開発計画]int型変数を宣言して、簡単な方法で説明した方法を思い出してください-変数スコープ(Day3)

int Age; //声明一个变量Age
  •  

ポインタを宣言するときは、タイプも指定する必要があります。また、intなどのこの型は、ポインタが指すメモリユニットに格納されている数値の型に対応します。

int *pAge; //声明一个指针变量
  •  

変数を宣言するときは、通常、変数を0に初期化します。同様に、ポインタを宣言するとき、ランダムメモリユニットを指すことは望ましくありません。したがって、ポインタはNULLに初期化されます。

int Age = 0;
int *pAge = NULL;
  •  

注:NULLに初期化されたポインターは、NULLポインターまたはヌルポインターと呼ばれます。ヌルポインター(つまり、pAge)は、値がゼロの標準ライブラリーで定義された定数です。

(2)&を使用して変数アドレスを取得します

記号&はと呼ばれ引用运算符ます。Ageが変数を表す場合、&Ageは変数が格納されているメモリアドレスになります。
以下に、変数Ageのアドレスを取得する簡単な例を示します。

#include<iostream>
using namespace std;
int main()
{
	int Age=18;
	cout<<"变量Age存放在内存中的地址是:"<<hex<<&Age<<endl;
	return 0;
}

実行後の出力結果:
ここに画像の説明を挿入します
注:プログラムの16進数は、出力形式が16進数であるためのものであり、これはアドレス表現の規則です。

(3)ポインタを使用してアドレスを格納する

ポインタはメモリアドレスを格納するために使用される変数であり、ポインタを宣言して変数のアドレスを取得する方法はわかっています。これで、それらを関連付け、ポインタを使用してアドレスを格納および取得できます。
ここに画像の説明を挿入します
上の図に示すように、今回は&Ageを介して直接アドレスを取得し、それをポインターpAgeに渡すことができます。
ポインタを宣言して初期化する小さな例を次に示します。

#include<iostream>
using namespace std;
int main()
{
	int Age = 18;
	cout<<"变量Age存放在内存中的地址是:"<<hex<<&Age<<endl;
	int *pAge = &Age;
	cout<<"指针pAge中存放的地址是:"<<hex<<pAge<<endl;
	return 0;
}

 

 

演算結果:
ここに画像の説明を挿入します
変数Ageのメモリに格納されているアドレス=ポインタpAgeに格納されているアドレスであることがわかります。参照演算子&がAgeのメモリアドレスを取得し、それをポインタpAgeに渡したと説明します。

(4)*を使用して指定されたデータにアクセスします

記号*は解除引用运算符とも呼ばれます。通常、それが有効なポインタpAgeである限り、* pAgeを介してアクセスできます指针pAge包含的地址处存储的值(アドレスではなく、アクセスアドレスに対応する値であることに注意してください)
簡単な例を次に示します。

#include<iostream>
using namespace std;
int main()
{
	int Age = 18;
	cout<<"Age = "<<Age<<endl;
	int *pAge = &Age;
	cout<<"*pAge = "<<*pAge<<endl; 
	return 0;
}

 

演算結果:
ここに画像の説明を挿入します
簡単に言えば、ポインタpAgeは変数Ageに対応するメモリユニットを指しているため、Ageに対応する値は記号*で取得できます。

2.動的メモリ割り当て

開発者がアプリケーションによって占有されているメモリをより適切に管理できるようにするために、C ++にはnewとdeleteの2つの演算子が用意されています。ポインタはメモリアドレスを含む変数であり、メモリを効率的に割り当てる上で重要な役割を果たします。

(1)新規/削除は動的にメモリを割り当てて解放します

newを使用してメモリブロックを割り当てる場合、成功すると、newは割り当てられたメモリへのポインタを返します。それ以外の場合は、例外が発生します。
newを使用して、int型番号にメモリを割り当てます。

int *pNum = new int;

newを使用して、複数の要素にメモリを割り当てます。

int *pNums = new int[10];

注:メモリを割り当てる新しい要求が発生した場合、システムの状態とメモリリソースの可用性に依存するため、要求が常に満たされる保証はありません。

newを使用して割り当てられたメモリは、最終的には対応する削除を使用して解放する必要があります。

  1. 1つの要素の場合:
int *pNum = new int;  //分配内存空间
-----程序块-----
delete pNum;  //释放内存空间
  1. 複数の要素の場合
int *pNums = new int[10];  //分配内存空间
-----程序块-----
delete[] pNUms;  //释放内存空间

注:割り当てられたメモリが使用されなくなった後は、削除して解放する必要があります。そうしないと、メモリリークが発生する可能性があります。

簡単な例を次に示します。メモリスペースを開いて経過時間を保存し、経過時間を保存するためのメモリアドレスを出力した後、割り当てられたメモリスペースを解放します。

#include<iostream>
using namespace std;
int main()
{
	int *pAge = new int;
	cout<<"请输入您的年龄:";
	cin>>*pAge;
	cout<<"存储年龄的内存地址是:"<<hex<<pAge<<endl;
	delete pAge;
	return 0;
}

演算結果:
ここに画像の説明を挿入します

(2)キーワードconstのポインター

単純な言語変数スコープ(Day3)説明した前の[C ++開発計画]では、変数がconstとして宣言されると、変数の値はライフサイクル全体で初期値に固定されます。この変数の値は変更できません。
ポインターも変数であるため、constをポインターに使用することもできます。constポインターには次の3つのタイプがあります。

  1. ポインタが指すデータは一定であり、変更することはできません。ただし、ポインタに含まれるアドレスは変更できます。つまり、ポインタは他の場所を指すことができます。
int Age = 18;
const int *pAge = &Age;  //不能更改pAge指向的数据Age的值
 2. 想将Age改为20,错误的做法
*pAge = 20;  //错误
 3. 正确的做法
int CopyAge = 20;
pAge = &CopyAge; //可改变指针指向的地址
  1. ポインタに含まれるアドレスは定数であり、変更することはできません。変更できるのは、ポインタが指すデータのみです。
int Age = 18;
int* const pAge = &Age;
*pAge = 20; //做法正确,可以改变值
  1. ポインタに含まれるアドレスとそれが指す値は定数であるため、どちらも変更できません。
int Age = 18;
const int* const pAge = &Age;

(3)ポインターVS配列

次のような配列を宣言する場合:

int Array[10];

コンパイラは、10個の整数を格納するための固定メモリを割り当てます。また、配列の最初の要素へのポインタも提供します。つまり、Arrayは最初の要素Array [0]へのポインタです。次のプログラムは、この関係を示しています。

#include<iostream>
using namespace std;
int main()
{
	int Array[10]={0,1,2,3,4,5,6,7,8,9};
	int *pNum = Array;
	cout<<"*pNum = "<<*pNum<<endl;
	cout<<"Array[0] = "<<Array[0]<<endl; 
	return 0;
}

演算結果:
ここに画像の説明を挿入します
配列名がポインタであり、最初の要素を指していることがわかります。

3.ポインタを使用する際のよくある間違い

(1)メモリリーク

newによって動的に割り当てられたメモリが不要になり、開発者がdeleteを使用してメモリを時間内に解放しない場合、メモリは予約され、アプリケーションに割り当てられます。これにより、他のアプリケーションで使用できるシステムメモリの量が減り、アプリケーションの実行速度が遅くなることもあります内存泄漏
たとえば、次のようになります。

int* pNums = new int[10];
-----程序块-----
//忘记进行delete[]

割り当てを要求されたメモリを削除し忘れると、メモリリークが発生しやすくなります。新しい要求を使用して動的メモリを割り当てる場合は、これに注意する必要があります。

(2)無効なポインタ

演算子*を使用してポインタを逆参照し、指定された値にアクセスする場合。ポインタが有効なメモリユニットを指していることを確認してください。そうでない場合、プログラムがクラッシュする可能性があります。
ポインタが無効になる理由はたくさんありますが、それらはすべてメモリ管理が不十分であることに起因します。ポインタが無効になる一般的な状況は次の2つだけです。

  1. ポインタを宣言する過程で、NULLに初期化されず、後でポインタに有効なアドレスが割り当てられませんでした。
  2. newを使用してポインタのダイナミックメモリを適用する場合、メモリの需要が特に大きいと、割り当てが成功せず、ポインタが無効になる可能性があります。たとえば、次のようになります。
int* pNums = new int[10000000000]; //申请的内存量太大,可能导致分配不成功

おすすめ

転載: blog.csdn.net/qq_14874791/article/details/107778460