【C言語】ポインタの基礎(詳しい知識をまとめる)

記事ディレクトリ

序文

C 言語学習におけるポインタ問題は、その知識ポイントが難しく、複雑ですが、非常に重要です。ポインタの知識については、Xiao Zhao が個別に説明します。この記事では、ポインタの基礎知識について詳しく説明します。高度な知識については、次のページで更新されます。将来、子供たちにもっと注目してください〜


提示:以下是本篇文章正文内容,下面案例可供参考,欢迎家人们批评指正!

1. ポインタとは

ポインタを理解するための 2 つの重要なポイント:

         1. ポインタはメモリ内の最小単位の番号、つまりアドレスです。

         2. 話し言葉におけるポインタは通常、メモリアドレスを格納するために使用される変数であるポインタ変数を指します。

& (アドレス演算子) を使用して、変数のメモリの実際のアドレスを取り出し、そのアドレスを変数 (ポインター変数) に格納できます。

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

    return 0;
}

32 ビット マシンでは、アドレスは 32 個の 0 または 1 で構成されるバイナリ シーケンスであり、アドレスは 4 バイトに格納する必要があるため、ポインター変数のサイズは 4 バイトにする必要があります。

64 ビット マシンには 64 のアドレス行があり、アドレスを格納するためのポインター変数のサイズは 8 バイトです。

 概要: ポインタ変数はアドレスを格納するために使用され、アドレスはメモリ ユニットを一意に識別します。

             ポインタのサイズは、32 ビット プラットフォームでは 4 バイト、64 ビット プラットフォームでは 8 バイトです。

2. ポインタとポインタの型

変数には、整数、浮動小数点などのさまざまな型があります。もちろん、ポインタにも型があります。 

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

char*型のポインタは、char型変数のアドレスを格納するために使用されます。

short* 型ポインタは、short 型変数のアドレスを格納するために使用されます。

int* 型のポインタは、int 型の変数のアドレスを格納するために使用されます。

ポインタ型の意味:

1. ポインタ + - 整数

コード例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.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);
	return 0;
}

操作結果:

 ポインタの種類によって、ポインタが 1 歩前進または後退する距離 (距離) が決まります。

例えば:

int* ポインタ + 1、整数をスキップする、つまり 4 バイト戻ることを意味します

char* ポインタ + 1。これは、文字タイプをスキップする、つまり 1 バイト戻ることを意味します。

short* ポインタ + 1、短い整数をスキップする、つまり 2 バイト戻ることを意味します

double* ポインタ + 1。double をスキップする、つまり 8 バイト戻ることを意味します。

2. ポインタの逆参照

ポインターの型によって、ポインターを逆参照する際の権限 (操作できるバイト数) が決まります。

例: char* ポインタ逆参照は 1 バイトのみにアクセスできます

            int*のポインタの逆参照は4バイトにアクセス可能

            double* ポインタの逆参照は 8 バイトにアクセスできます

3、ワイルドポインター 

ワイルド ポインタとは、ポインタが指す位置が不明である (ランダム、不正確、明確に制限されていない) ことです。

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

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

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

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;
}

3) ポインタが指したスペースが解放される

2. ワイルドポインタを回避する方法 

1) ポインタの初期化

2) 範囲外のポインタに注意してください

3) ポインタは解放するスペースを指し、時間内に NULL を設定します

#include <stdio.h>
int main()
{
    int *p = NULL;
    //....
    int a = 10;
    p = &a;
    if(p != NULL)
   {
        *p = 20;
   }
    return 0;
}

4) ローカル変数のアドレスを返さないようにする

5) ポインタを使用する前に、ポインタの有効性を確認してください。

4. ポインタ演算

1. ポインタ + - 整数

例 1:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	double arr[5] = { 0 };
	double* p = arr;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%lf ", *(p + i)); 
	}

	return 0;
}

例 2:

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	int* p = arr; 
	//数组名就是首元素的地址arr->&arr[0]
	int i = 0;

	for (i = 0; i < 10; i++)
	{
		*(p + i) = i + 1;
	}
	/*for (i = 0; i < 10; i++)
	{
		*p = i + 1;
		p++;
	}*/

	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	//1~10
	return 0;
}

2. ポインタ-ポインタ

例 1:

int my_strlen(char* str)
{
	char* start = str;
	while (*str)
		str++;
	return str - start;  //指针-指针
}

int main()
{
	char arr[] = "abcdef";
	//int len = strlen(arr);
	int len = my_strlen(arr);    //函数调用结果与strlen()结果一样
	printf("%d\n", len);
	return 0;
}

例 2:

int main()
{
	//两个指针相减的前提是:指针指向同一块连续的空间
	int arr[10] = { 0 };
	printf("%d\n", &arr[9] - &arr[0]);
	printf("%d\n", &arr[0] - &arr[9]);

	int a = 10;
	char c = 'w';
	printf("%d\n", &a - &c);
	return 0;
}

注: 2 つのポインターを減算する前提は、ポインターが同じ連続スペースを指していることです。

3. ポインタの関係演算

int main()
{
	float arr[5] = { 1,2,3,4,5 };
	float* p;
	int i = 0;
	for (p = &arr[4]; p >= &arr[0]; p--)
	{
	    *p = 0;
		printf("%lf ", *(p + i));
	}
	return 0;
}

標準規制:

        配列要素へのポインタは、配列の最後の要素の後のメモリ位置へのポインタと比較できますが、最初の要素より前のメモリ位置へのポインタとは比較できません。 

5. ポインタと配列

(配列とポインタは同じものではありません)

配列には要素のグループ、連続した空間を格納でき、配列のサイズは要素の数によって異なります。

ポインタはアドレスを格納する変数で、4/8 バイトです。

接続:

        配列名はアドレス(ポインタ)です

        配列の最初の要素のアドレスがポインター変数に与えられると、ポインターを介して配列にアクセスできるようになります。

#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]);
    return 0;
}

例:

int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	int* p = arr; //指针存放数组首元素的地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

6. セカンダリポインタ

ポインタ変数も変数であり、変数にはアドレスがあるのですが、ポインタ変数のアドレスはどこに格納されているのでしょうか?

セカンダリ ポインターの操作は次のとおりです。

         *ppa は、pa を見つけるために ppa 内のアドレスを逆参照します。 *ppa は実際に pa を訪問します。

int b = 20;
*ppa = &b;  //等价于 pa = &b;

        **ppa は最初に *ppa までの pa を検索し、次に pa: *pa を逆参照してから、 

**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

7、ポインタ配列

ポインタの配列はポインタですか、それとも配列ですか?

ポインタの配列は配列、つまりポインタの配列です。

int arr1[5];  //整型数组
char arr2[6]; //字符数组
int* arr3[5]; //整型指针数组

例:

int main()
{
	int a = 10;
	int b = 20;
	int c = 30;
	int d = 40;
	int e = 50;
	int* arr3[5] = { &a,&b,&c,&d,&e }; //存放整型指针的数组
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", *(arr3[i]));
	}
	return 0;
}


やっと

 Happy time is always short. 以上が今日お話したいことですが、この記事では Xiao Zhao によるポインタの基礎知識とユースケースについての予備知識を詳しく紹介します。家族は批判や修正を歓迎します。Xiao Zhao同志は更新を続けています。継続的な学習の動機は、1つのボタンと3つの連続リンクによるBaoziのサポートです〜

          

おすすめ

転載: blog.csdn.net/weixin_70411664/article/details/128835475