C言語の高度な使い方_(11)_ポインタ

目次

1 ポインタの基本概念 

2 セカンダリ ポインタ 

3 ポインタの算術演算

4 つの無効ポインタ

5つの定数ポインタ

6 ポインタ配列と配列ポインタ

ポインタの 1 つの配列

2 つの配列ポインタ

7 ポインタと配列の関係

 1 ポインタと 1 次元配列の関係

 2 ポインタと二次元配列の関係

 配列要素にアクセスする 3 つの方法


1 ポインタの基本概念 

1 アドレス: メモリ内の異なるバイトを区別するために使用される番号

2 ポインタ: アドレスはポインタ、ポインタはアドレス

3 ポインタ変数:アドレスを格納する変数

4 &: このシンボルは、メモリ空間内の変数の最初のアドレスを取得し、式の型をアップグレードするために使用されます。たとえば、int型--->>int*型です。

5 *: この記号が = 式の右側にある場合、ポインタが指す空間の値を取得することを意味します (取得される空間のサイズはポインタの種類によって異なります)。式 = の左側にある場合は、ポインタが指す空間に右側の値が代入されることを意味します。式のタイプをダウングレードする効果もあります。たとえば、int* 型--->>int 型です。

次の図に示すように、整数 100 を格納するために 4 バイトが使用され、整数変数の最初のアドレスへのポインタを格納するために 8 バイトが使用されます。

2 セカンダリ ポインタ 

変数のアドレスを格納する変数をポインタと呼びますが、ポインタを格納したいポインタはどうなるでしょうか? 次に、セカンダリ ポインタを使用します。

整数 = 0;

int *pnum = #num;

int **ppnum = &pnum;                                                                                                               

説明するプログラムはこちら

#include <stdio.h>

int main(int argc, char const *argv[])
{
          int num = 100;
          int *pnum = &num;
          int **ppnum = &pnum;

          printf("num = %d\n",num);
          printf("*pnum = %d\n",*pnum);
          printf("**ppnum = %d\n",**ppnum);
          printf("&num = %p\n",&num);
          printf("pnum = %p\n",pnum);
          printf("*ppnum = %p\n",*ppnum);
          printf("&pnum = %p\n",&pnum);
          printf("ppnum = %p\n",ppnum); 
        
          return 0;
}

 

ただし、セカンダリ ポインターは C の 2 か所で使用されます。

 1 関数本体が関数本体の外でポインタ変数の値を変更したい場合、ポインタ変数のアドレスは第 2 レベルのポインタになります。

 2 ポインター配列にパラメーターを渡す場合、配列の配列名は配列の最初のポインター要素へのポインターになります。

3 ポインタの算術演算

+ - ++ --

ポインタのオフセットは、ポイントされたデータ型のバイト空間のサイズです。

int* :4

文字* :1

ダブル* :8

int** :8

4 つの無効ポインタ

ボイド *p;

多くの場合、ストレージ メモリのアドレスを指すために使用され、領域のサイズを指す意味はありません。

void* 型のポインターは、* または ++ -- のフェッチに関連する操作には使用しないでください。

void * 型ポインターと他の型のポインター間の変換には、必須の型変換は必要ありません。

使用

関数のパラメーターとして、またはすべての型と互換性のあるポインターを表す関数の戻り値として使用されます。

1 memcpy (void *dest, const void *src, size_t n); メモリコピー関数のパラメータ定義

2 memcmp(const void *s1,const void *s2,size_t n);

質問例: メモリアドレスが 0x2000 の空間に整数 100 を代入してください (0x2000 は void * 型のアドレスです)

           (*(int *)((void*)0x2000)) = 100; または (* (int *)0x2000) = 100;

5つの定数ポインタ

1. const int *p;

2. int const *p;

3. int *const p;

4. const int *const p;

5. int const *const p;

1 と 2 は同等で、const は *p によって変更され、p が指すスペースは変更できません (読み取り専用) が、p は変更できます。(strcpy 関数の const char *src パラメーターなど、ソースを変更することはできません)。使用することはできますが、変更することはできません。

3では、constはpによって変更され、pは変更できませんが、*pは変更できるため、初期化する必要があります。プログラムでは、初期化時にpはスペースのみを指すことができ、ポイントすることはできません。他の空間へのポインターですが、p 値が指す空間を変更するために使用できます。(たとえば、配列の配列名は常に最初の要素の最初のアドレスを指し、最初の要素の値を変更できます)。

4と5は同等で、constはpと*pで変更され、ポインタが指すアドレスと空間は変更できません。初期化する必要があります。

6 ポインタ配列と配列ポインタ

ポインタの 1 つの配列

ポインタの配列:

ポインタの配列は配列、つまりポインタの配列であり、この配列内の各要素はポインタです。

int *p[5];

たとえば、上記では配列 p が定義されており、配列には 5 つの要素があり、各要素は 8 バイト、合計 40 バイトで、各要素は整数変数へのポインターです。

C 言語では、通常、整数ポインター配列はあまり使用されず、文字ポインター配列 (char *pstr[5]) が使用されます。

理解するためのコード

#include <stdio.h>

int main(int argc, char const *argv[])
{
          char *pstr[5] = {"hello","world","how","are","you",};
          for(int i = 0;i < 5;i++)
          {
                    printf("str[%d] = %s\n",i,pstr[i]);
          }
          return 0;
}

一般に、2 次元配列は文字列の格納に使用され、ポインタの配列は文字列の操作に使用されます。

たとえば、バブル ソートを使用して文字列の配列を並べ替えます。この場合、文字列の代わりにアドレスが交換されます。

以下のコード例に示すように、

in(int argc, char const *argv[])
{
          char *pstr[5] = {"hello","world","how","are","you",};
          int i = 0;
          int j = 0;
          char *ptmp = NULL;
          for(i = 0;i < 5 -1;i++)
          {
                    for(j = 0;j < 5 -1 - i;j ++)
                    {
                              if(strcmp(pstr[j],pstr[j + 1]) > 0)
                              {
                                        ptmp = pstr[j];
                                        pstr[j] = pstr[j + 1];
                                        pstr[j +1] = ptmp;
                              }
                    }
          }

          for(i = 0; i < 5; i++)
          {
                    printf("%s\n",pstr[i]);
          }
          return 0;
}

2 つの配列ポインタ

 配列ポインタはポインタであり、ポインタは配列を指し、ポインタは 8 バイトを占有します。

int (*a)[5];

int a[5];

&a:int (*)[5]

1 1 次元配列の配列名と演算の場合、値不変型は配列ポインタにアップグレードされます。

2 配列ポインタに対する * 演算の場合、値不変型は配列の最初の要素へのポインタにダウングレードされます。

コードを説明する

#include <stdio.h>

int main(int argc, char const *argv[])
{
          int (*p)[5] = NULL;
          int a[5] = {1,2,3,4,5,};
          p = &a;

          printf("a = %p\n",a);
          printf("&a = %p\n",&a);
          printf("*a = %d\n",*a); 
          printf("*&a = %p\n",*&a);
          printf("========================\n");
          printf("p = %p\n",p);
          printf("p + 1 = %p\n", p+1);
          printf("*p = %p\n",*p);
          printf("*p + 1 = %p\n", *p+1); 
          return 0;
}

 7 ポインタと配列の関係

 1 ポインタと 1 次元配列の関係

 int a[5] = {1,2,3,4,5};

配列の array-name は、配列の最初の要素へのポインタです。

a = &a[0]

配列要素にアクセスする方法: a[n] = *(a + n) 

 2 ポインタと二次元配列の関係

2次元配列の配列名aは、配列の1行目の要素を指す配列ポインタである。

#include <stdio.h>

int main(int argc, char const *argv[])
{
          int a[2][3] = {1,2,3,4,5,6};

          printf("================================\n");
          printf("&a[0][0] = %p\n",&a[0][0]);
          printf("&a[0][1] = %p\n",&a[0][1]);
          printf("&a[0][2] = %p\n",&a[0][2]);
          printf("&a[1][0] = %p\n",&a[1][0]);
          printf("&a[1][1] = %p\n",&a[1][1]);
          printf("&a[1][2] = %p\n",&a[1][2]);
          printf("================================\n");
          printf("a = %p\n",a);
          printf("a + 1 = %p\n",a + 1);
          printf("================================\n");
          printf("a[0] = %p\n",a[0]);
          printf("a[0] + 1 = %p\n",a[0] + 1);
          printf("a[1] = %p\n",a[1]);
          printf("a[1] + 1 = %p\n",a[1] + 1);
          printf("================================\n");
          printf("*a[0] = %d\n",*a[0]);
          printf("*(a[0] + 1)= %d\n",*(a[0] + 1));
          printf("*a[1] = %d\n",*a[1]);
          printf("*(a[1] + 1) = %d\n",*(a[1] + 1));
          printf("================================\n");
          printf("*a = %p\n",*a);
          printf("*(a + 1) = %p\n",*(a + 1));
          return 0;
}

 

 配列要素にアクセスする 3 つの方法

a[m][n] = *(a[m] + n) = *(*(a + m) + n)

*(p + m * N + n)

おすすめ

転載: blog.csdn.net/m0_58193842/article/details/128369481