Xiaobai は C++ を徹底的に学び続けています

  • セクション 1 ポインタの基本概念

  • 0x01、変数アドレス:

        変数とはメモリ アドレスの略で、C++ では変数が定義されるたびにシステムがその変数にメモリを割り当て、メモリにはアドレスが割り当てられます。
 

C++ は演算子 & を使用してメモリ内の変数の開始アドレスを取得します。
        構文: &変数名

  • 0x02、ポインタ変数:

        ポインタ変数はポインタと呼ばれ、メモリ内の変数の開始アドレスを格納するための専用の特殊な変数です。
        構文: データ型 *変数名;

        データ型は、正当な C++ データ型 (int、char、double、またはその他のカスタム データ型) である必要があります。
        アスタリスク* は乗算のアスタリスクと同じですが、このシナリオでは、変数がポインタであることを示すためにアスタリスクが使用されます。

  • 0x03、ポインタに値を代入

        整数、浮動小数点、文字、その他のデータ型変数のいずれであっても、そのアドレスは 16 進数です。整数型変数のアドレスを格納するには整数ポインタを使用します。
        文字変数のアドレスを格納するには文字ポインタを使用します。浮動小数点変数のアドレスを格納するには浮動小数点ポインタを使用します。
        構文: pointer=&変数名;

  • 0x04、ポインタが占有しているメモリ

        ポインタも変数です。変数の場合、メモリ領域を占有します。
        64 ビット システムでは、ポインタの種類に関係なく、占有されるメモリは 8 バイトです。

    注:
        ポインタの代入操作は、一般に「変数へのポインティング」とも呼ばれ、ポインタ先の変数のデータ型は「基本型」と呼ばれます。
        ポインタのデータ型が基本型と一致しない場合、コンパイル中に警告が表示されます。ただし、それらの型はキャストできます。

    C++ では、ポインタは複合データ型です。複合データ型とは、他の型に基づいて定義されたデータ型を指します。プログラムでは、int は整数型で、int * は整数ポインタ型です。< a i=1> int * は変数の宣言に使用でき、sizeof 演算子で使用でき、データ型の強制変換に使用できます。一般的には、int * をデータ型として扱います。

#include<stdio.h>
#include<iostream>

using namespace std;
int main()
{
	char a = 65;
	int b = 1234;
	float c = 3.14;
	double d = 3.1415926;

	char* pa = &a;
	int* pb = &b;
	float* pc = &c;
	double* pd = &d;

	cout << "a的地址是:" << (void*) & a << endl;    // (char*)是强制类型转换
	cout << "b的地址是:" << (void*)&b << endl;
	cout << "c的地址是:" << (void*)&c << endl;
	cout << "d的地址是:" << (void*)&d << endl;

	cout << "sizeof(a)=:" << sizeof(a) << endl;
	cout << "sizeof(b)=:" << sizeof(b) << endl;
	cout << "sizeof(c)=:" << sizeof(c) << endl;
	cout << "sizeof(d)=:" << sizeof(d) << endl;

	cout << "pa的地址是:" << (int*)pa << endl;  // (int*)是强制类型转换
	cout << "pb的地址是:" << (int*)pb << endl;
	cout << "pc的地址是:" << (int*)pc << endl;
	cout << "pd的地址是:" << (int*)pd << endl;

	cout << "sizeof(*pa)=:" << sizeof(*pa) << endl;
	cout << "sizeof(*pb)=:" << sizeof(*pb) << endl;
	cout << "sizeof(*pc)=:" << sizeof(*pc) << endl;
	cout << "sizeof(*pd)=:" << sizeof(*pd) << endl;
	

	return 0;
}

  • セクション 2 ポインタの使用

ポインタ変数を宣言した後、値を代入する前は内部に乱雑な値が存在するため、この時点ではポインタは使用できません。
    ポインタは変数のアドレスを格納するため、(変数名が変数を表すのと同じように) ポインタ名はアドレスを表します。
    * 演算子が呼び出されます。間接値 または逆参照 (逆参照) 演算子。メモリ内のそのアドレスに格納されている値を取得するためのポインターに使用できます。* は乗算記号でもあります。C++ は、コンテキストに基づいて乗算を参照するか逆参照を参照するかを決定します。
    変数と変数へのポインタは、同じコインの表裏のようなものです。

#include<iostream>

using namespace std;
int main()
{
	int a = 8;
	int* pa = &a;

	cout << "a=" << a << endl;
	cout << "*pa=" << *pa << endl;

	*pa = 9;

	cout << "a=" << a << endl;
	cout << "*pa=" << *pa << endl;

	a = 12;

	cout << "a=" << a << endl;
	cout << "*pa=" << *pa << endl;

	return 0;
}

  • セクション 3 ポインタは関数のパラメータとして使用されます 

 関数の仮引数がポインタとして宣言されている場合、呼び出し時に実引数のアドレスが渡されます。実引数のアドレスは仮引数に格納されます。関数内では、メモリは逆参照によって直接操作されます。データ、
    は実数の値を変更できます。この方法は一般にアドレス転送またはアドレス転送として知られています。
        
        値の転送: 関数の仮パラメータは通常の変数です。
        アドレスを渡す意味:
            実パラメータの値は関数内で変更できます。
            メモリのコピーを削減し、パフォーマンスを向上させます。

#include<iostream>

using namespace std;

void bijiao(int a, int b, int *max, int* min);

int main()
{
	int a = 5, b = 9, max = 0, min = 0;
	bijiao(a, b, &max, &min);
	cout << "max=" << max << "\nmin=" << min << endl;
	return 0;
}

void bijiao(int a, int b, int* max, int* min)
{
	*max = a > b ? a : b;
	*min = a < b ? a : b;
}

  • セクション 4 const を使用したポインタの変更

0x01, 定数ポインター
        構文: const データ型 * 変数名;
        メモリ アドレスの値は逆参照によって変更できません (元の変数名は変更できます)。

    注:
        指す変数 (オブジェクト) は変更できます (以前は変数 a を指していましたが、後で変数 b を指すように変更できます)。
        通常、関数の仮パラメータを変更するために使用され、関数内のメモリ アドレスの値を変更したくないことを示します。
        仮パラメータとして使用すると、ポイントされたオブジェクトを変更できますが、変更しても意味がありません。
        仮パラメータの値を変更する必要がない場合は、プログラムを読みやすくするために const 変更を追加することをお勧めします。

    0x02、ポインタ定数
        構文: データ型 * const 変数名
        指す変数(オブジェクト)は変更できません。

    注:
        は定義と同時に初期化する必要があります。初期化しないと意味がありません。
        メモリ アドレスの値は逆参照によって変更できます。

    0x03、定数ポインター定数
        構文: const データ型* const 変数名
        指す変数 (オブジェクト) は変更できません。 dereferenced このメソッドはメモリ アドレスの値を変更します。
        よく引用されます。

    定数ポインタ: ポインタは変更できますが、ポインタが指す値は変更できません。
    ポインタ定数: 指すポインタは変更できませんが、ポインタが指す値は変更できます。
    定数ポインタ定数: 指すポインタは変更できず、ポインタが指す値も変更できません

    メモリ シークレット: * はポインタを表します。最初にポインタを読み取ります。ポインタが前にある場合、ポインタは変更できません。
    定数ポインタ: const データ型 * 変数名
    ポインタ定数: データ型 * const 変数名

#include<iostream>

using namespace std;
int main()
{
	int a = 3, b = 8;

	//常量指针
	const int* p = &a;
	//*p = 6;   不能通过解引用的方法修改内存地址中的值(用原始的变量名是可以修改的)。
	a = 6;
	cout << "a=" << a << endl;
	p = &b;
	cout << "b=" << b << endl;

	//指针常量
	int* const p2 = &a;
	*p2 = 7;
	cout << "a=" << a << endl;
	//*p2 = &b;   指向的变量(对象)不可改变
	cout << "b=" << b << endl;

	//常指针常量

	const int* const p3 = &a;
	//*p3 = 4;   指针指向的值不可以更改
	//p3 = &b;	 指针指向不可以改
}

  • セクション 5 void キーワード

C++ では、void は型なしとして表され、主に 3 つの用途があります。

        関数の戻り値は void です。これは、関数に戻り値がないことを意味します。
                void func(int a, int b)
                {                     


        関数のパラメータは void で埋められています。これは、関数がパラメータを必要としない (またはパラメータ リストが空のままである) ことを意味します。
                int func(void)
                {                     //関数本体コード。                     0 を返す。


        関数の仮パラメータは void* です。これは、関数が任意のデータ型のポインタを受け入れることを意味します。
                注:
                     は変数の宣言に void を使用できません。実際の変数を表すことはできません。
                    void* ポインタは直接逆参照できません (他の型のポインタに変換する必要があります)。
                    他の型のポインタを void* ポインタに代入する場合、変換は必要ありません。
                    void* ポインターを他のタイプのポインターに割り当てるには、変換が必要です。

#include<iostream>

using namespace std;

void fun(string name, void* p)
{
	cout << name << "的地址是:" << p << endl;
	cout << name << "的值是:" << *(char *)p << endl;  // char*强制类型转换,只能解引用char类型的值,想解引用a的值就要int*强制转换
	cout << name << "的值是:" << *(int *)p << endl;
}

int main()
{
	int a = 8;
	char b = 'X';
	cout << "a的地址是:" << &a << endl;
	cout << "b的地址是:" << &b << endl;
	cout << "b的地址是:" << (void *) & b << endl;  // 这样就能正确显示地址了

	//下面调用函数
	fun("a", &a);
	fun("b", &b);

	fun("B", &b);

	return 0;
}

  • セクション 6 C++ メモリ モデル

スタックとヒープの主な違い:
    1. さまざまな管理方法: スタックはシステムによって自動的に管理され、範囲外になると自動的に解放されます。ヒープは手動で解放する必要があります。プログラム中には解放されず、プログラムの終了時にオペレーティング システムによってリサイクルされます。
    2. 異なる領域サイズ: ヒープ メモリのサイズは物理メモリ領域によって制限されますが、スタックは残念ながら小さく、通常は 8M のみです (システム パラメータは変更可能)

    3. 割り当て方法が異なります。ヒープは動的に割り当てられ、スタックには静的割り当てと動的割り当てがあります (どちらも自動的に解放されます)。
    4. 割り当て効率が異なります: スタックはシステムによって提供されるデータ構造であり、コンピュータは下部のスタックをサポートします。スタックのプッシュおよびポップには特別な命令があります。これはより効率的であり、ヒープは C++ 関数ライブラリによって提供されるもので構成されます。
    5. 断片化が発生するかどうか: スタックの場合、スタックのプッシュとポップには厳密な順序 (先入れ、後出し) があり、断片化は発生しません。一方、頻繁な割り当ては行われません。ヒープを解放すると、メモリ空間に不連続性が生じ、断片化が発生しやすくなります。
        断片が多すぎると、パフォーマンスの低下につながります。
    6. 拡張方法が異なります。スタックは下方向に拡張し、メモリ アドレスは降順で割り当てられますが、ヒープは上方向に拡張し、メモリ アドレスは昇順で割り当てられます。

  • セクション 7 メモリの新規割り当てと削除を動的に行う

ヒープ メモリを使用するには 4 つの手順があります
    1. ポインタを宣言します。
    2. new 演算子を使用してメモリの一部を適用します。システムから取得し、ポインタがこのメモリを指すようにします。
    3. ポインタを逆参照することで、このメモリを変数のように使用します。
    4; このメモリが使用されなくなった場合は、削除演算子を使用して解放します。

    メモリを適用するための構文: 新しいデータ型 (初期値); //c++11 は、{}
    をサポートします。アプリケーションが成功すると、アドレスが返されます。アプリケーションが失敗すると、空のアドレスが返されます (失敗は今のところ考慮されていません)。
    メモリを解放するための構文: delete address;
    メモリの解放は失敗しません (お金の返済は失敗しません)。

    注:
        動的に割り当てられたメモリには変数名がありません。メモリ内のデータは、それを指すポインタを介してのみ操作できます。
        動的に割り当てられたメモリが使用されなくなった場合は、削除を使用して解放する必要があります。そうしないと、システムのメモリが使い果たされる可能性があります。
        動的に割り当てられたメモリの宣言期間はプログラムの宣言期間と同じであり、プログラムが終了する際、解放されていなければシステムが自動的に再利用します。
        ポインタの有効期限が切れても、指すメモリは解放されません。
        割り当てられたメモリをたどるためにポインタを使用する場合、そのポインタが失われることはありません。

#include<iostream>

using namespace std;

int main()
{
	int* p = new int(99);
	cout << "p=" << *p << endl;
	*p = 999;
	cout << "p=" << *p << endl;
	delete p;
}

  • セクション 8 二次ポインタ

ポインタとはポインタ変数の略で、変数でもあり、変数はアドレスを持ちます。
    ポインタは、通常の変数のアドレスを格納するために使用されます。
    セカンダリ ポインタは、ポインタ変数のアドレスを格納するために使用されます。
    セカンダリ ポインターを宣言する構文:
            データ型** ポインター名;
            ポインターの使用には 2 つの目的があります。 a>         関数では、通常の変数のアドレスが渡される場合はポインタが仮引数として使用され、ポインタのアドレスが渡される場合は二次ポインタが仮引数として使用されます。 。                 2. 動的に割り当てられたメモリのアドレスを保存します。
                1. アドレスを渡します。

#include<iostream>

using namespace std;

void func(int** pa)
{
	*pa = new int(6);
	**pa = 5;
	cout << "函数内:pa = " << pa << "   *pa = " << *pa << "   **pa ="<< **pa << endl;
	
}

int main()
{
	int a = 8;
	cout << "a=" << a <<"   &a = "<< &a << endl;

	int* p = &a;
	*p = 9;
	cout << "p = " << p << "   *p=" << *p << "   &p = "<< &p << endl;
	int** pa = &p;
	cout << "pa = " << pa << "   *pa = " << *pa << endl;

	func(pa);
	cout << "函数外:pa = " << pa << "   *pa = " << *pa << "   **pa =" << **pa << endl;

	delete pa;
	return 0;
}

  • セクション 9 ヌルポインタ

C および C++ では、0 または NULL を使用して NULL ポインターを表すことができます。
    ポインタを宣言した後、値を割り当てる前に、ポインタがどのアドレスも指していないことを示す null を指すようにします。

    1. null ポインタを使用した結果
        null ポインタが逆参照されると、プログラムがクラッシュします。
        null ポインタに対して delete 演算子を使用すると、システムはその操作を無視し、例外は発生しません。したがって、メモリが解放された後は、ポインタも null を指す必要があります。
        プログラムの堅牢性を確保するために、関数内に仮パラメータが null ポインタかどうかを判断するコードが必要です。

        NULL ポインタにアクセスすると例外が発生するのはなぜですか?
        NULL ポインターによって割り当てられたパーティション: その範囲は 0x00000000 ~ 0x0000FFFF です。このスペースは空きです。空きスペースには、対応する物理メモリが存在しないため、このスペースに対して書き込み操作を行うと例外が発生します。 NULL ポインタは、プログラムが対応する物理メモリを常に持たないアドレスです。この状態を常に確保するには、NULL ポインタ領域を人為的に分割する必要があり、これが本質的に NULL ポインタ分割です。

    2. null ポインタを表すために 0 と NULL を使用すると、あいまいさが生じます。C++11 では、null ポインタ (void*)0 を表すために nullptr を使用することを推奨します。
        NULL はC++ では 0 です。これは、C++ の void* 型が他の型への暗黙的な変換を許可していないためです。そのため、以前は C++ で null ポインターを表すために 0 が使用されていましたが、整数型がオーバーロードされると、上記の問題が発生します。そのため、
        C++11 では nullptr が追加されており、どのような状況でも null ポインターを表すことが保証され、上記の状況は発生しません。そのため、NULL の代わりに nullptr を使用することをお勧めします。 、NULL は 0 が使用されたものとみなされます。

        注: Linux プラットフォームで nullptr を使用する場合は、コンパイル時に -std=c++11 パラメーターを追加する必要があります。

#include<iostream>

using namespace std;
int main()
{
	int* p = 0;
	cout << "p=" << p << "    *p=" << *p << endl;  // 会在* p 解引用的时候,程序意外退出。

	


	return 0;
}

  • セクション 10 ワイルド ポインター

ワイルド ポインタは、ポインタが無効な (正当な) アドレスを指していることを意味します。
    プログラム内でワイルド ポインターにアクセスすると、プログラムがクラッシュする可能性があります。
    ワイルド ポインタが表示される主な状況は 3 つあります:
    1. ポインタが定義されているときに初期化されていない場合、その値は不確実です (ランダムなポインティング)。 ) 一息)。
    2. ポインタが動的に割り当てられたメモリをポイントしている場合、メモリが解放された後、ポインタは空にはなりませんが、ポイントされたアドレスは無効になります。
    3. ポインタが指す変数が変数のスコープを超えています (変数のメモリ空間はシステムによって再利用されています)。

    回避方法:
        1. ポインタを定義する際、ローカル参照がない場合、ポインタは nullptr に初期化されます。
        2. 動的に割り当てられたメモリが解放されると、nullptr に設定されます。
        3. 関数はローカル変数のアドレスを返してはなりません。
        注: ワイルド ポインタは null ポインタよりもはるかに有害です。プログラム内でワイルド ポインタにアクセスすると、プログラムがクラッシュする可能性があります。可能性はありますが、確実ではありません。
        プログラムのパフォーマンスが不安定になるため、プログラムのデバッグが難しくなります。
 

#include<iostream>

using namespace std;
int main()
{
	int* p = new int{ 8 };
	cout << "p = " << p << "*p= " << *p << endl;
	delete p;
	p = nullptr;
	cout << "p = " << p << "*p= " << *p << endl;
	return 0;
}

  • セクション 11 関数ポインタとコールバック関数

関数のバイナリ コード メモリの 4 番目の領域のコード セグメント、関数のアドレス、およびメモリ内のその開始アドレス。
    関数のアドレスをパラメータとして使用すると、関数内で他の関数を柔軟に呼び出すことができます。

    関数ポインタを使用する 3 つの手順:
        a. 関数ポインタを宣言します。
            通常のポインタを宣言する場合は、ポインタの型を指定する必要があります。 。同様に、関数ポインタを宣言するときは、関数の型も指定する必要があります。関数の型は戻り値とパラメータ リストを参照します (関数名と仮パラメータ名は参照しません)。
            関数ポインタの宣言は次のとおりです: Type (*関数ポインタ名) (パラメータ タイプ 1、パラメータ タイプ 2)
                                        

        b. 関数ポインタが関数のアドレスを指すようにします。
        c. 関数ポインタを介して関数を呼び出します。

#include<iostream>

using namespace std;

int jia(int a, int b)
{
	return a + b;
}

int jian(int a, int b)
{
	return a - b;
}

int main()
{
	int a = 8, b = 6;
	int input = 0;

	int(*pjia)(int, int);
	int(*pjian)(int, int);
	pjia = jia;
	pjian = jian;

	cout << "a+b=" << pjia(a, b) << endl;
	cout << "a-b=" << pjian(a, b) << endl;

	return 0;
}

  • セクション 12 1 次元配列の基本概念

 1. 配列の基本概念
    定義: 配列は、データのグループを格納できる同じデータ型を持つ変数のグループです。
    配列を宣言する構文: データ型 配列名 [配列の長さ];
    注: 配列の長さは整数である必要がありますが、定数でも構いません。変数または式モードにすることができます。

    C90 では、配列のサイズを知るために定数式を使用する必要があると規定されており、C99 では整数の非定数式の使用が許可されています。テスト後、VS
    では整数の非 const 式を使用できますが、変数は使用できません。ただし、変数は Linux でも使用できます。

    2. 配列の使用:
        添字を使用して配列内の要素にアクセスできます。配列の添字は 0 から始まります。
        配列内の各要素の特性と使用法は、単一の変数の特性と使用法とまったく同じです。
        構文: 配列名 [配列の添字]
    注:
        配列の添字は整数である必要があり、定数にすることもできます. 変数にすることもできます。
        有効な配列添字値は 0~ (配列長 -1) です。

    3. 配列が占有するメモリ
        メモリ内で配列が占有する空間は連続しています。
        sizeof (配列名) を使用して、配列全体が占めるメモリ領域のサイズを取得します (C++ 基本データ型にのみ適用可能)。

    4. 配列の初期化
        宣言時の初期化:
            配列型 配列名 [配列長] = {値 1, 値 2.. ...}
            データ型配列名 [] = {値 1, 値 2...}
            配列型配列名 [配列長 ] = {0 }; //すべての要素を 0 に初期化する
            配列型配列名 [配列長] = {}; //すべての要素を 0 に初期化する
        注: a>         a>         Linux では、memcpy() 関数を使用する場合、ヘッダー ファイル #include<string.h>         関数プロトタイプ: void * menmcpy (void *dest, const void* src, size_t n);         memcpy() 関数を使用して、配列内のすべての要素を同じサイズの別の配列にコピーします。 (C++ の基本データ型でのみ使用されます)    6. 配列のコピー         Linux では、memcpy 関数を使用するにはヘッダー ファイル #include< が必要であることに注意してください。 string. h>         関数プロトタイプ: void *menmset(void* s, int C, size_t n); menset() 関数を使用して、配列内のすべての要素を 0 にクリアします。 (C++ の基本データ型でのみ使用されます)     5. 配列をクリアします             C++11 標準では等号は必要ありません。             配列内のすべての要素を 0 に初期化したい場合は、{} に 0 を 1 つだけ入力するか、何も入力しません。
            {} 内のデータが配列長未満の場合、残りのデータは 0 で埋められます。ただし、配列内の特定の値が欠落している可能性があるため、これはお勧めできません。






 


#include<iostream>

using namespace std;

void print(int arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << "------------------------------------------"<<endl;
		cout << "arr[" << i << "]=" << arr[i] << endl;
		cout << "取地址arr[" << i << "]=" << &arr[i] << endl;
	}
}

int main()
{
	int arr[3] = { 1,2,3};
	
	print(arr, 3);

	memset(arr, 0, sizeof(arr));  //清空数组  最后一个参数最好用sizeof()查询字节数,要么输入数组的字节数,否则失败
	print(arr, 3);

	return 0;
	
}

  • セクション 13 1 次元配列とポインタ

    1. ポインタ演算
        整変数に 1 を加算すると、その値は 1 ずつ増加します。
        ただし、ポインタ変数 (アドレス値) ) は、それが指すデータ型のバイト数に等しい量だけ 1 増加します。
    2. 配列のアドレス
        a. メモリ内で配列が占める空間は連続しています。
        b. C++ は、配列名を配列の 0 番目の要素のアドレスとして解釈します。
        c. 配列の 0 番目の要素のアドレスと配列の最初のアドレスの値は同じです。
        d. 配列の n 番目の要素のアドレスは次のとおりです: 配列の最初のアドレス + n
        e. C++ コンパイラは配列名 [添え字] を * として解釈します。 (配列の最初のアドレス + 添字)

    3. 配列の本質
        配列は、連続した空間を占めるメモリの一部であり、配列名は配列の 0 番目の要素のアドレスとして解釈されます。 C++ でこのメモリを操作するには、
        配列解釈方式とポインタ方式の 2 つの方法があり、これらは同等です。

    4. 配列名は必ずしもアドレスとして解釈されるとは限りません
        ほとんどの場合、C++ は配列名を配列の 0 番目の要素のアドレスとして解釈します。 sizeof 演算 データ名に文字が使用されている場合、
        は配列全体が占有するメモリ領域のバイト数を返します。
        ポインタの値は変更できますが、配列名は定数であるため変更できません。

  • セクション 14 関数のパラメータとして使用される 1 次元配列

1. ポインタの配列表現
        C++ では、ポインタは配列の処理に使用されます
        C++ コンパイラは、配列名 [添え字] を * として解釈します。 (配列の最初のアドレス + 添字)
        C++ コンパイラはアドレス [添字] を *(アドレス + 添字) として解釈します

    2. 1 次元配列が関数のパラメータとして使用される場合
        1 次元配列が関数のパラメータとして使用される場合、渡すことができるのは配列のアドレスと配列の長さ。ただし、配列の最後の要素を示します。
        記述方法は 2 つあります:
                    void func(int * arr, int len);
                    void func(int arr[ ], int len);
        注:
            関数では、配列表記またはポインタ表記を使用できます。
            関数内では、ポインタに sizeof 演算子を使用しないでください。ポインタは配列名ではありません。
                int arr[] は int*arr に置き換えられます。これは、両方の関数ヘッダーが正しいことを証明します。なぜなら、C++ では、
            が次の場合 (およびその場合にのみ) int*arr と int arr[] の意味が関数ヘッダーまたは関数プロトタイプで使用されるからです。同じ。これらはすべて、arr が int
            ポインターであることを意味します。ただし、配列表記 (int arr[]) は、arr が int を指すだけでなく、int 配列の最初の int も指すことをユーザーに思い出させます。
            ポインタが配列の最初の要素を指す場合、本書では配列表記を使用します。ポインタが独立した値を指す場合、ポインタ表記は
            となります。使用済み。他のコンテキストでは、int*arr と int arr[] は異なる意味を持つことを忘れないでください。たとえば、 inttip[] を使用して関数本体でポインタを宣言することはできません
            。

#include<iostream>
using namespace std;

void func(int* p, int len, int a[])
{
	cout << "这是在函数里面:" << endl;
	cout << "sizeof(a)="<<sizeof(a) << endl;
	for(int i=0;i<len;i++)
	{ 
		cout << "a[" << i << "]的地址是:" << &a[i] << "值是:" << a[i] << endl;
		cout << "p[" << i << "]的地址是:" << p + i << "值是:" << *(p + i) << endl;
	}
	
}

int main()
{
	int a[] = { 8,9,2,5,7,3,6 };
	int* p = a;
	for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
	{
		cout << "a[" << i << "]的地址是:" << &a[i] << "值是:" << a[i] << endl;
		cout << "p[" << i << "]的地址是:" << p+i << "值是:" << *(p+i) << endl;
	}
	cout << "下面是把数组a的第2个元素的地址赋值给p2,结果会不同p2从下标为2的元素开始,a还是从0开始" << endl;
	int * p2 = &a[2];
	for (int i = 0; i < 5; i++)
	{
		cout << "a[" << i << "]的地址是:" << &a[i] << "值是:" << a[i] << endl;
		cout << "p2[" << i << "]的地址是:" << p2 + i << "值是:" << *(p2 + i) << endl;
	}

	cout << "这是在函数外面:" << endl;
	cout << "sizeof(a)=" << sizeof(a) << endl;
	func(p, sizeof(a) / sizeof(a[0]), a);
}

おすすめ

転載: blog.csdn.net/xingyuncao520025/article/details/133449229