高度なポインター: 配列ポインター、ポインター配列、文字ポインター (超詳細な説明、Xiaobai は一目で理解できます!!!!!!)

目次

I.はじめに

2. ポインタ配列と配列ポインタの判別方法

1.文字通りに受け取る

2. シンボルの側面から理解する 

3. ポインターの配列

1. ポインタ配列の応用 

2. ポインタ配列の入力

 4.配列ポインタ

五、文字ポインタ

1. 文字ポインタの使い方

2. 文字ポインタの誤りやすいポイント

六、相互励まし


I.はじめに

ポインタの予備知識がある場合、現時点では、基本的なポインタを理解して書き込むことができるポインタにとどまっていることがわかります. ポインタが実際に頻繁に使用される場所は、実際にはポインタ配列、配列ポインタ、および文字のアプリケーションです.ポインター。これらのことは、質問をブラッシングしたり、大物のコードを読んだりする通常の練習に現れ続けるため、この知識は常に私を悩ませてきました. 私の慎重な調査の後、私はそれを書き留めてあなたと共有します.

基本を忘れてしまった場合は、私の以前の基本的なポインターの理解を参照してください。

(メッセージ数 295) ポインターの基本的な理解 (シンプルでわかりやすく、超詳細!!!)_sunny-ll のブログ - CSDN ブログ

2. ポインタ配列と配列ポインタの判別方法

1.文字通りに受け取る

「配列ポインタ」と「ポインタの配列」は、名詞の途中に「の」という単語を追加すれば、中心を知ることができます—

配列ポインタ: ポインタですがどのようなポインタですか? 配列へのポインター。

ポインターの配列: 配列ですがどのような配列ですか? ポインターの配列。

2. シンボルの側面から理解する 

優先順位を ()>[]>* のように指定する必要があるため、次のようになります。

      (*p)[n]: 優先度に従って、最初に括弧内を調べます。次に、p はポインターです。このポインターは 1 次元配列を指し、配列の長さは n です。これが「配列ポインター」です。 、つまり配列ポインタです

     *p[n]: 優先順位に従って、最初に [] を見て、次に p が配列であり、次に * と組み合わせると、この配列の要素はポインター型になり、合計 n 要素になります。これは「配列」です。つまり、ポインタの配列です

上記の 2 つの分析によると、何が p であり、次にフレーズの中心語、つまり配列「ポインター」とポインター「配列」が何であるかがわかります。

3. ポインターの配列

配列内のすべての要素がポインターを保持する場合、それをポインターの配列と呼びます。その一般的な形式は次のとおりです。

type * ポインタ名 [ ]

配列であり、配列の要素はすべてポインタです.配列が占有するバイト数は、配列自体のサイズによって決まり、各要素はポインタです. 

例: char *arr[]={"Sunday", "Monday"}、2 つのポインターが格納されます。最初のポインターは文字列 "Sunday" を指し、2 番目のポインターは文字列 "Monday" を指します。 

文字ポインターは 2 次元配列よりも高速で効率的であるため、ポインターの配列の最も重要な用途は、複数の文字列に対して操作を実行することです。

 

1. ポインタ配列の応用 

コード例のデモンストレーション:

#include <stdio.h>
int main()
{
    //定义三个整型数组
	int a[5] = { 1,2,3,4,5 };
	int b[5] = { 6,4,8,3,1 };
	int c[5] = { 2,5,8,6,1 };
    //定义一个存放指向整型变量的指针的数组arr
    int* arr[] = { a,b,c };
    //通过接引用打印出三个一维数组的元素
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
        {
		    printf("%d ", *(arr[i]+j));
	    }
        printf("\n");
    }
	return 0;
}

結果:

1 2 3 4 5

 6 4 8 3 1

 2 5 8 6 1

上記の arr を逆参照するには多くの方法があり、それらはすべて同等です. 例を挙げましょう: 

#include<stdio.h>
int main()
{
	int i = 0;
	int a[3][4] = { {1,2,3,4} ,{5,6,7,8} ,{9,10,11,12} };//定义一个二维数组
	int* pa[3];//定义一个指针数组
	for (i = 0; i < 3; i++)//给指针数组赋值
		pa[i] = a[i];
    printf("指针数组的内容为:\n");
	for (i = 0; i < 3; i++)//打印出指针数组的内容
	{
		int j;
		for (j = 0; j < 4; j++)
			printf("%d ", *(*(pa + i) + j));
		printf("\n");
	}
    //以下均为不同方式的解引用操作
    printf("不同解引用操作的结果为:\n");
	printf("%d,%d\n", a[1][1], *(pa[1] + 1));
	printf("%d,%d\n", a[1][1], *(*(pa+1) + 1));
	printf("%d,%d\n", a[1][1], (*(pa + 1))[1]);
	printf("%d,%d\n", a[1][1], pa[1][1]);
    return 0;
}

結果:

ポインター配列の内容は次のとおりです。

1 2 3 4 5
6 7 8
9 10 11 12

さまざまな逆参照操作の結果は次のとおりです。

6,6
6,6
6,6
6,6

上記の例から、逆参照には多くの方法があることがわかります。それらの同等の形式は次のとおりです。 

*( pa[i] + j )         //等价于 *( a[i] + j )

*( *(p+i) + j ) // 等了了 *( *(a+j) + j )

( *(p+i) )[ j ] // 等了了( *(a+i) )[ j ]

p[ i ][ j ] // 等了了了 a[i][j]

重要: ポインター配列は、文字列配列と組み合わせて使用​​することもできます。次の例を参照してください。 

#include <stdio.h>
int main(){
    char *str[3] = {"lirendada","C语言","C Language"};
 
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    return 0;
}

デート

c言語

C言語

注: 文字列の最初のアドレスは、文字列自体ではなく文字配列 str に格納されます. 文字列自体は他のメモリ領域にあり、文字配列とは別です.

ポインタ配列の各要素の型が char * の場合のみ、上記のようにポインタ配列に値を割り当てることができ、他の型はできません。

2. ポインタ配列の入力

ポインターの配列に文字列を入力する方法は?

1. ポインターは、初期化中に次のように割り当てられます: char *p = "hello world!" または char *p[3]={"aa", "abc", "ggdd"}; 2. 初期化中に適用されます
。定義されているだけで初期化されていないポインタはメモリ空間を
指さないため、ポインタが指す場所に値を割り当てることはできません。これが、ポインターのみが定義されている場合、Xalloc または new を使用して初期化用のスペースを適用する理由です。

スペースを申し込む 

malloc 関数を使用して、ポインターの配列にスペースを割り当てます。

malloc は、必要に応じてプログラムに割り当てることができるメモリ空間を動的かつランダムに割り当てる方法です。
例: (char*)malloc(sizeof(char)*20) は、
20 個の char 型データ サイズに動的にスペースを割り当て、返されたポインター型を char 型ポインターにキャストすることを意味します。

スペースを開く操作は、ループ ステートメントを使用して実行できます。たとえば、 for char *p[10]; を適用できます。

for( i=0 ; i<10 ; i++ ) 
{
   p[i] = ( char *) malloc ( sizeof ( char ) * N ); //为每个指针申请开设N字符的存储空间
}

C 言語を使用して、ポインターの配列を入力し、出力します。

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    char* str[5] = {}; ///5为5个字符串,后面的大括号为初始化
    int i;
    for (i = 0; i < 5; i++)
    {///指针数组如果没有初始化赋值,则要申请空间,切记,否则会出错,这里的100为每个字符串的元素个数最多为100
        str[i] = (char*)malloc(100);
    }
    for (i = 0; i < 5; i++)
    {
        scanf("%s", str[i]); ///这里不用加& ,因为str本身是地址
        // gets(str[i]);
    }
    for (i = 0; i < 5; i++)
    {
        printf("%s ", str[i]);
        // puts(str[i]);
    }
    printf("\n");
    for (i = 0; i < 5; i++)
    {
        free(str[i]);///最后要free,逐个free
    }
    return 0;
}

 操作結果:

ポインター配列のアプリケーション トピックについては、次の記事を参照してください。

(メッセージ数 295) Array of Pointers_Layne... のブログ - CSDN Blog_Array of Pointers

要約: 上記の説明によると、ポインター配列が 2 次元配列の作成、文字列の入力ストレージに適用できることが 明確にわかります。通常のアプリケーションでは実際には文字列の入力ストレージに使用されます。例えば、タイトルは5つの文字列を入力して長さを比較したり、辞書順で文字列を連続入力したり、文字列を並べ替えたりする必要があるのですが、このときポインタ配列を使うととても便利です!! ! !

 4.配列ポインタ

配列ポインターは、ほとんどの場合、主に 2 次元配列の作成と適用に使用されます。そのタイプは次のとおりです。

int (*p)[4] = a ; 

配列 a を指すポインター p を表し、配列 a の各行には 4 つの要素があります。

かっこは、*p が type の配列へのポインターであることを示します。int [4]これは、a に含まれる各 1 次元配列の型です。

[]The priority is high than that must be added *. ()Naked と書かれている場合、 p は 2 次元配列ポインターではなく、ポインターの配列になることをint *p[4]理解する必要があります。int *(p[4])

配列名 a も式の p に相当するポインタに変換されます!

ポインター p を使用して 2 次元配列の各要素にアクセスする方法を見てみましょう。上記の定義によると:

1) p配列 a の先頭、つまり行 0 をポイントし、p+11 行進めて行 1 をポイントします。

2) *(p+1)アドレスのデータ、つまり最初の行のデータ全体をフェッチすることを示します。これはデータの行ですが、複数のデータであり、行 1 の 0 番目の要素ではないことに注意してください。コードの理解:

#include <stdio.h>
int main(){
    int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
    int (*p)[4] = a;
    printf("%d\n", sizeof(*(p+1)));
    return 0;
}

   実行結果: 16

   意味: 行には 4 つの int 整数があるため、4*4=16 は行のデータを表します

3) *(p+1)+1 は、1 行目の最初の要素のアドレスを表します。それを理解する方法は?

*(p+1)は、単独で使用する場合のデータの最初の行を意味し、式に配置すると、データの最初の行の最初のアドレス、つまり、変数の0番目の要素のアドレスに変換されます。行全体が使用されるため、最初の行 データには実際の意味はなく、この状況が発生すると、コンパイラはそれを行の 0 番目の要素へのポインターに変換します。

4)  *(*(p+1)+1)1 行目の最初の要素の値を示します。明らかに、* を追加することは、アドレスのデータをフェッチすることを意味します。

上記の結論によると、次の同値関係を簡単に導き出すことができます。

a+i == p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)

配列ポインターへの 2 次元配列の適用:

#include <stdio.h>
int main(){
    int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
    int(*p)[4];
    int i,j;
    p=a;
    for(i=0; i<3; i++){
        for(j=0; j<4; j++) printf("%2d  ",*(*(p+i)+j));
        printf("\n");
    }
    return 0;
}

 操作結果:

0 1 2 3
 4 5 6 7
 8 9 10 11

五、文字ポインタ

1. 文字ポインタの使い方

(1) 1文字

 char  ch='w';
 char *p=&ch;
 //这里的p就是个字符指针 我们可以通过解引用p去改变ch中存的字符'w'。
 *p='s';

(2)ひも


   const char* pstr="hello bit.";//这里是把一个字符串放到pstr指针变量里了吗? 
   printf("%s\n", pstr);

(2) について
は、まず「hello bit.」は定数文字列で、ここの char* には文字列の最初の文字のアドレス、つまり h のアドレスが格納されています。

定数文字列: 逆参照によって変更することはできないため、const を使用して、char* ポインターが逆参照してコンテンツを変更することを制限する必要があります。

概要: 定数文字列の最初の文字 h のアドレスは、ポインター変数 pstr に格納されます。

2. 文字ポインタの誤りやすいポイント

コード例:

#include <stdio.h>
int main()
{
    char str1[] ="hello bit.";
    char str2[] ="hello bit.";
    
    const char* str3="hello bit.";    
    const char* str4="hello bit.";
    
    if(str1==str2)
       printf("str1 and str2 are same\n");    
    else
       printf("str1 and str2 are not same\n");   
           
    if(str3==str4)
       printf("str3 and str4 are same\n");    
    else
       printf("str3 and str4 are not same\n");       
    return 0;
}

str1 と str2 は同じではなく、str3 と str4 は同じなのはなぜですか?


まず、例 1 では、ここでの 2 つの if 比較はすべてアドレスです。

str1 と str2 の比較は、配列の最初の要素のアドレスです。これは、配列がメモリ内のスペースを開くため、str1 と str2 のアドレスが異なるためです。
str3 と str4 は文字ポインタで, 文字列の最初の文字のアドレスを比較します. これら 2 つのポインタに格納されている内容は "hello bit." です. これらは同じ定数文字列であり, メモリ内の同じ定数文字列
は1部なので、str3とstr4のアドレスは同じです。

六、相互励まし

以下は、配列ポインタ、ポインタ配列、および文字ポインタに関する私の理解です. 理解していない、または問題を見つけた友人がいる場合は、コメント欄で教えてください. 同時に、私は引き続き私の理解を更新します.コールバック ポインタ qsort 関数、続行してくださいフォローしてください! ! ! ! !

 

 

おすすめ

転載: blog.csdn.net/weixin_45031801/article/details/127381406