ポインタの基本的な概要と詳細な説明

1.ポインタとは

ポインタと言えば、基礎を身につけた学生はそれがメモリアドレスであることを知っているかもしれませんが、ポインタをよりよく理解するためには、コンピュータのメモリから始めなければなりません。ポインタをよく理解するための前提条件は、メモリとは何かを理解することです。

1.メモリ

メモリはコンピュータの非常にコアなハードウェアデバイスであり、プログラムを作成する際の非常に重要なリソースでもあります。
私たちはそれを次のように理解することができます:記憶は非常に長いホテルの廊下です。この廊下は多くの部屋で構成されています。部屋のサイズは8ビット(1バイト)です。16進数の方法を使用して各部屋をドア番号でカウントします。番号、この家の番号はポインタである私たちの記憶のアドレス、ポインタはここで私たちの家の番号です
ここに画像の説明を挿入しますここでは、メモリサイズを測定するためにGを使用することがよくあります。

Gには10億バイトあります

2.外部メモリと内部メモリ

メモリと外部メモリの両方がデータの保存に使用されますが、CPUはメモリにしかアクセスできません。注意深い学生は、コンピュータを購入するときに、一般的にそのような選択肢があることに気付くかもしれません:
ここに画像の説明を挿入します
ここで16Gがメモリサイズです(メモリバーはプラスメモリです)サイズ)、512Gは外部メモリサイズです。(メカニカルハードドライブとソリッドステートドライブはすべて外部ストレージです)

メモリと外部メモリの違い:異なる揮発性、異なるパフォーマンス、異なるストレージ期間、異なるアクセス権

3.ポインタ

ポインタは、メモリユニットのアドレス(番号)を格納する変数です。
小さなコードの助けを借りて詳細に説明しましょう:

#include <stdio.h>
int main()
{
    
    
 int a = 10;//一个变量开辟四个房间
 int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
   //将a的地址存放在p变量中,p就是一个之指针变量。
 return 0;
}

4.セカンダリポインタ

ポインタは変数なので、ポインタのアドレスはどこにありますか?

第2レベルのポインターでは、第2レベルのポインターの変数は、無限ループである第3レベルのポインターに格納されます。
ここに画像の説明を挿入します

この種の複数のポインタは通常使用されないので、理解してください。発生した場合は、typedef(エイリアスの変更)を使用して簡略化できます。

5.まとめ

ポインタは変数であり、アドレスを格納するために使用される変数です。(ポインタに格納されている値はアドレスとして扱われます)
アドレスは変数なので、メモリ内のサイズもありますよね?

32ビットオペレーティングシステムでは、ポインタ変数のサイズは4バイトです
。64ビットオペレーティングシステムでは、ポインタ変数のサイズは8バイトです。

2つ、ポインタとポインタタイプ

1.ポインタの種類と定義

ポインタも変数です。変数には、整数、浮動小数点など、さまざまなタイプがあります。ポインタの
種類はありますか?正確には:はい。
ポインタの種類は次のように表現します。

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

さまざまなポインタタイプは、それが指すメモリ空間のサイズを表します。

int *、char *、およびshort *と同様に、*が付いたデータ型がポインターです。
32ビットオペレーティングシステムでは、ポインタ変数のサイズは4バイトです
。64ビットオペレーティングシステムでは、ポインタ変数のサイズは8バイトです。

したがって、ポインタ型自体のサイズは固定されていることに注意してください。
ここでは、ポインタが指すメモリ空間と、ポインタが配置されているメモリ空間を区別する必要があります。
ここに画像の説明を挿入します

2.ポインタ型の意味

固定サイズなので、int *、char *、short *の他の意味は何ですか?

2.1逆参照サイズのアクセス許可

ポインターのタイプによって、ポインターを逆参照するときの権限(数バイトを操作できる)が決まります。たとえば、char *ポインタの逆参照は1バイトにしかアクセスできませんが、int *ポインタの逆参照は4バイトにアクセスできます。

#include<stdio.h>
#include<stdlib.h>
int main()
{
    
    
 int n = 0x11223344;
 char *pc = (char *)&n;
 int *pi = &n;
 *pc = 0;   //重点在调试的过程中观察内存的变化。
 *pi = 0;   //重点在调试的过程中观察内存的变化。
 system("pause");
 return 0;
}

2.2ポインタアクセスの範囲

ポインタの種類によって、ポインタを1ステップ前後に移動できる距離が決まります。(例:intタイプ+1アドレス転送4バイト、charタイプ+1アドレス転送1バイト)

#include<stdio.h>
#include<stdlib.h>
int main()
{
    
    
	int n = 10;
	char* pc = (char*)&n;
	int* pi = &n;
	printf("%p\n", &n);
	printf("%p\n", pc);
	printf("%p\n", pc+1);
	printf("%p\n", pi);
	printf("%p\n", pi+1);
	system("pause");
	return 0;
}

ここに画像の説明を挿入します3番目は1つの数字(1バイト)を
追加し、5番目は4つの数字(4バイト)を追加します

3、ワイルドポインタ

1.コンセプト

概念:ワイルドポインターとは、ポインターが指す位置が不明(ランダム、不正確、明確に制限されていない)であることを意味します。ポインター変数が定義されたときに初期化されていない場合、その値はランダムであり、ポインター変数の値はは別の変数です。アドレスとは、ポインタがアドレスが不確実な変数を指していることを意味します。現時点では、参照解除とは不確実なアドレスにアクセスすることであるため、結果は不明です。

全文は違法な住所を訪問することです

2.ワイルドポインタの原因

ここでは、ポインタアクセスの不正なアドレスの一般的な状況について注意深く説明します。

2.1ポインタが初期化されていない

#include <stdio.h>
int main()
{
    
    
 int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
 return 0;
}

初期化はなく、アドレスも指定されていないため、ランダムな値が表示されます。

2.2範囲外のポインタアクセス

この問題は、アレイでは非常に一般的です。

#include <stdio.h>
int main()
{
    
    
    int arr[10] = {
    
    0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
    
    
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0}

正当なアドレスのみを逆参照でき、ワイルドポインターの逆参照は未定義の動作です。

2.3ポインタが指すスペースが解放されます

関数内のローカル変数は、この種の問題を起こしやすいです。

3.ワイルドポインタを避けます

1.ポインターの初期化
2.ポインターが範囲外になることに注意してください。3。ポインター
がNULLに設定されていても、スペースを指します
。4。使用する前にポインターの有効性を確認してください。

4、ポインタ演算

1.ポインタの加算と減算の整数

次の要素と前の要素にアクセスすることです。

#include <stdio.h>
int main()
{
    
    
	int arr[3] = {
    
     1, 2, 3 };
	int* p = &arr[1];
	
	printf("%d ", *p);
	printf("%d ", *(p - 1));
	printf("%d ", *(p +1));
	system("pause");
	return 0;
}

ここに画像の説明を挿入します

2.ポインターマイナスポインター

ポインタが連続したメモリアドレス上にある場合は、ポインタをポインタから減算できます。
ポインタ減算の結果は、2つのアドレス間のいくつかの「要素」です。
意味あり:

#include <stdio.h>
int main()
{
    
    
	int arr[4] = {
    
     1, 2, 3, 4 };
	int* p1 = &arr[0];
	int* p2 = &arr[2];
	printf("%d\n", p2- p1);
	system("pause");
	return 0;
}

ここに画像の説明を挿入します

3.ポインタ関係演算

ポインタは関係演算を実行することもできます。ポインタの関係演算には、<、>、<=、> =、==、!=が含まれます。

注:ポインター比較操作(<、>、<=、> =)では、同じ連続有効メモリー・スペースを指すために2つのポインターが必要であるため、意味があります。

簡単なコードを使用して、ポインターの関係演算を体験できます。

#include <stdio.h>
int main()
{
    
      
	int num = 10;
	int* p = &num;
	if (p) {
    
    
		printf("不是空指针\n");
	} else {
    
    
		printf("是空指针!\n");
	}
	system("pause");
	return 0;
}

ここに画像の説明を挿入します


#include <stdio.h>
int main()
{
    
      
	int num = 10;
	int* p = &num;
	if (p != NULL) {
    
    
		printf("不是空指针\n");
	} else {
    
    
		printf("是空指针!\n");
	}
	system("pause");
	return 0;
}

ここに画像の説明を挿入します
ここで私達は見ることができます:
if(p!= NULL)はif(p)と同等です
同様のことを要約することができます:
if(p == NULL)はif(!p)と同等です
ここのコードは、ポインターが関係演算を実行できることを示しているだけです。

5、ポインタと配列

ポインターと配列は、ポインターの問題で最も簡単に混乱しますが、ポインターと配列は2つのまったく異なるものであり、類似点と相違点を理解するだけで済みます。
最も重要なポイントは次のとおりです。

C言語では、配列名は暗黙的にポインターに変換されることがよくあります。
ポインターは、配列のように動作する[]を使用して添え字を付けることもできます。

1.ポインタ配列と配列ポインタ

ポインタの配列は一種の配列であり、通常のint、char、その他のデータの代わりに、int *、char *などのポインタを格納します。
int * arr [5] = {0};

int arr[5]={
    
    0};//(普通数组)
//可以理解成arr[5]里面的是int
int* arr[]={
    
    0};
//arr[5]里的是int*

配列ポインタは、配列を指すポインタの一種です。
注:これは、配列名で表される最初の要素のアドレスとは異なります。

//我们可以通过打印地址求证
//指针+1是跳过一个元素
int arr[5]={
    
    0};
int(*p)[5]=&arr;
printf("%p\n",arr);
printf("%p\n",arr+1);//首元素指针
printf("%p\n",&arr+1);//int(*)[5]

最初の要素のアドレスが4で、配列ポインタが20であることがわかります。

2.アレイの名前は何ですか

次のコード行を記述します。

#include <stdio.h>
int main()
{
    
    
 int arr[10] = {
    
    1,2,3,4,5,6,7,8,9,0};
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    system("pause");
    return 0;
}

ここに画像の説明を挿入します配列名は、配列の最初の要素のアドレスと同じであることがわかりました。
したがって、配列名は配列の最初の要素のアドレスを表します。
したがって、次のようなコードを実装できます。

int arr[3]={
    
    0,1,2};
int* p=arr;//p存放的是数组首元素的地址

3.ポインタの暗黙的な変換

この暗黙の変換は、次の場合にのみ発生しますC言語、他の言語は発生しません
次に、C言語からポインターへの暗黙的な変換について詳しく説明します。

1.1。アレイ名は操作に参加します

私たちは知っています配列は±で操作できませんが、ポインターは加算および減算できます、これが発生している場合は、この時点で暗黙の変換が行われたことを示しています。

このとき、配列名は、配列のアドレスではなく、最初の要素のアドレスを指します。配列のアドレスは、配列ポインターによってポイントされます(配列ポインターとポインター配列は、配列内の高度な項目です。後で要約します)

#include <stdio.h>
int main()
{
    
      
	int arr[3] = {
    
     0,1,2 };
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(arr + 0));
	system("pause");
	return 0;
}

ここに画像の説明を挿入します12はarr配列のバイト数を表し、
4は最初の要素ポインターを指すバイト数であり、固定されています4(私の場合は32ビット設定です)

1.2。関数パラメータの転送

#include <stdio.h>
void change(int arr){
    
    
	printf("%d\n", sizeof(arr));
}
int main()
{
    
      
	int arr[3] = {
    
     1,2,3 };
	printf("%d\n", sizeof(arr));
	change(arr);
	system("pause");
	return 0;
}

ここに画像の説明を挿入します
12はarr配列のバイト数を表し、
4は最初の要素ポインターを指すバイト数であり、固定されています4(私の場合は32ビット設定です)

4. []ポインタの操作

[]は、配列のインデックスを取得する操作です。これは、ポインタでも発生する可能性があります。
注:ポインタインデックスは負にすることができ、配列は固定範囲内にのみ存在できます

#include <stdio.h>
int main()
{
    
       
	int arr[4] = {
    
     1, 2, 3, 4 };
	int* p = arr + 1;
	 //这个操作是允许的,数组下标一定是 [0, size-1] 范围
	// 但是指针的下标不一定. 取决于指针初始情况下指向谁. 
	printf("%d\n", p[-1]);
	printf("%d\n", *(p - 1));
	system("pause");
	return 0;
}

ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/zhaocx111222333/article/details/109703060