C言語のポインタを詳しく解説


序文

ポインタは C 言語において非常に重要な概念であり、C 言語の重要な機能です。正しく柔軟に使用すると、複雑なデータ構造を効果的に表現できます。メモリ アドレスを通じてデータを直接処理すると、プログラムがシンプル、コンパクト、効率的になります。


1. ポインターの基本概念:

コンピュータでは、すべてのデータはメモリに保存されます。各記憶ユニットのサイズは 1 バイトです。管理を容易にするために、各記憶ユニットに番号を付ける必要があります。この番号が記憶ユニットの「アドレス」です。ユニットには固有のアドレスがあります。

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

  1. ポインタはメモリ内の最小の記憶単位の番号、つまりメモリアドレスです。
  2. 私たちが話し言葉で話すポインタは、通常、ポインタ変数 (変数のメモリ アドレス ペアを格納するために使用されます) を指します。

ここに画像の説明を挿入します
& (アドレス演算子) を通じて変数のアドレスを取得し、そのアドレスをポインター変数に格納できます。

#include <stdio.h>
int main()
{
    
    
	int a = 10;//在内存中开辟一处空间
	printf("%d", a);//运行结果为10
	int* p = &a;//这里取出变量a的地址,放到指针变量p中
	*p = 20;//通过对p解引用找到a来修改a的值
	printf("%d", a);//运行结果为20
	return 0;
}

ポインターについての理解を深めるために例を使用してみましょう:
ここに画像の説明を挿入します
たとえば、a がホテルにチェックインする場合、a を見つけたい場合は、部屋ごとに検索する必要があります。そして効率は大幅に低下します。最善の方法は部屋番号から見つけることです。これは正確かつ効率的です。ここでの居住者は変数aに相当し、部屋番号はaのメモリアドレスとなり、アドレスを逆参照することでaを求めることができます。

ポインタ変数は何バイトを占有しますか?

  • 32 ビット マシンでは、アドレスは 32 個の 0 または 1 で構成されるバイナリ シーケンスであり、アドレスは 4 バイトの空間に格納する必要があるため、ポインタ変数のサイズは 4 バイトにする必要があります。
  • 同様に、64 ビット マシンを使用している場合、アドレスを格納するにはポインター変数のサイズは 8 バイトである必要があります。

注: ポインタ変数のサイズは、格納されるデータの種類とは関係なく、同じ環境では同じサイズになります。

2. ポインタの種類:

変数には整数、浮動小数点などのさまざまな型があることは誰もが知っています。ポインタには型がありますか?

int main()
{
    
    
	int* p1 = NULL;//NULL是空指针
	char* p2 = NULL;
	float* p3 = NULL;
	return 0;
}

上記のコードを見ると、ポインタは type+ として定義されている* ことがわかります。

例えば:

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

それでは、この定義にはどのような意味があるのでしょうか?

1. ポインタ ± 整数:

#include <stdio.h>
int main()
{
    
    
	char a = 'a';
	char* pa = &a;
	int b = 10;
	int* pb = &b;
	printf("%p\n", pa);//0x00D5FEBB
	printf("%p\n", pa + 1);//0x00D5FEBC
	printf("%p\n", pb);//0x00D5FED0
	printf("%p\n", pb + 1);//0x00D5FED4
	return 0;
}

上記のコードを実行した結果を見てください。

  • char*+1 型の変数はアドレスを 1 バイト増加します
  • int*+1 型の変数のアドレスは 4 バイト増加します

概要: ポインタのタイプによって、1 ステップの前後の距離 (距離) が決まります。

2. ポインタの逆参照:

#include <stdio.h>
int main()
{
    
    
	int n = 0x11223344;
	char* p1 = (char*)&n;//将n地址强制转化为char*类型
	int* p2 = &n;
	*p1 = 0;//n变为0x11223300
	*p2 = 0;//n变为0x00000000
	return 0;
}

要約:

  • ポインタ変数の型によって、逆参照する際の権限(操作できるバイト数)が決まります。
  • 例: char のポインタ逆参照は 1 バイトのみにアクセスできますが、int は 4 バイトにアクセスできます。

3. ポインタ演算:

1. ポインタ ± 整数:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	int* p = &arr[0];
	printf("%d\n", *p);//结果为1
	printf("%d\n", *(p + 1));//结果为2
	return 0;
}

2. ポインター - ポインター:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	int* p1 = &arr[0];
	int* p2 = &arr[1];
	printf("%d", p2 - p1);
	//运行结果为1,说明p2和p1之间有1个变量
	return 0;
}

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

3. ポインタの関係演算:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	int* p1 = &arr[0];
	int* p2 = &arr[1];
	if (p2 > p1)//指针的比较
	{
    
    
		printf("yes");//运行结果为yes
	}
	return 0;
}

標準規制:

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

4. ポインタと配列:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	printf("%p", arr);//00F3CC00
	printf("%p", &arr[0]);//00F3CC00
	//可以看到数组名和数组首元素地址是一样的
	return 0;
}

結論: 配列名は配列の最初の要素のアドレスを表します。 (2つの場合を除く)

2 つの状況:

  1. 配列名は、sizeof(arr) のように、sizeof の中にあり、配列全体を表します。
  2. &arr、このとき、配列名は配列全体も表します。

5. 二次ポインタ:

ポインタ変数も変数です。変数には当然アドレスがあり、二次ポインタにはポインタのアドレスが格納されます。

#include <stdio.h>
int main()
{
    
    
	int a = 10;
	int* pa = &a;//pa存放a的地址
	int** ppa = &pa;//ppa存放pa的地址
	**ppa = 20;//把a的值改成了20
	int b = 30;
	*ppa = &b;//相当于pa中存了b的地址
	return 0;
}

6. ポインタ配列:

ポインタ配列は配列ですか、それともポインタですか? ?
答えは「配列」です。ポインタ変数を格納する配列です
整数配列には整数が格納され、文字配列には文字が格納されることがわかります。
ポインタ配列には当然ながらポインタ変数が格納されます。
ここに画像の説明を挿入します


終わり

ポインタは諸刃の剣です。上手に使えばプログラミングの効率が上がりますが、下手に使えばプログラム エラーが多く発生します。そのため、C 言語を学ぶ人は誰でもポインタをしっかり学ぶことが重要です。
以上が予備的な注意事項の内容ですが、このブログを読み終えたばかりの方の参考になれば幸いです。

おすすめ

転載: blog.csdn.net/weixin_61661271/article/details/124558398