C++言語における配列ポインタとポインタ配列の徹底的な分析


################################################################################
もちろん私たちはすべて最も簡単な内装タイプから始めて、最後に私はいくつかの普及をします.まず基本的な形式を見て、私たちはここからスタートします!
--------------  ----------------
int a=10;
int *p=&a;

-------------     -----------
int b=20;
int *p=&b;
int **p2p=&p;

-------------    -----------------
int c[10];//    ,  10     
          file://             
         
--------------    --------------------
int *p[10];//    ,  10     
            file://             
           
--------------    --------------------
int (*p)[10];//    ,          
             file://  10        
 
上記の簡単な形式は私たちがまず理解しなければならないことであり、これは基本的な知識である.同時に、c++言語レベルで変数宣言に関する部分では、接尾辞結合変数の優先度が接頭辞よりも高いという重要な知識ヒントも得られます.私たちの上の例の最後の2つを見ると、配列ポインタの宣言を実現するために、私たちは融通しなければなりません.()を用いて優先度の変更を実現し,配列ポインタの宣言を実現した.
################################################################################
配列、配列のポインタ、ポインタの配列、概念が多すぎます.私が概念を受け入れたとき、私はこれらの複雑なものを簡単にしたいと思っていました.私は怠け者なので、概念を簡略化して、覚えやすいです.これらの概念の本質を認識しなければなりませんこれにより概念を簡略化し、記憶の難易度を減らすことができる.
まずプログラムを見てください.
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
 int vInt=10;
 int arr[2]={10,20};
 
 int *p=&vInt;
 int **p2p=&p;
 
 int *parr[2]={&vInt,&vInt};
 int (*p2arr)[2]=&arr;

 cout<<"Declaration [int vInt=10] type=="<<typeid(vInt).name()<<endl;
 cout<<"Declaration [arr[2]={10,20}] type=="<<typeid(arr).name()<<endl;
 cout<<"Declaration [int *p=&vInt] type=="<<typeid(p).name()<<endl;
 cout<<"Declaration [int **p2p=&p] type=="<<typeid(p2p).name()<<endl;
 cout<<"Declaration [int *parr[2]={&vInt,&vInt}] type=="<<typeid(parr).name()<<endl;
 cout<<"Declaration [int (*p2arr)[2]=&arr] type=="<<typeid(p2arr).name()<<endl;

 return 0;
}
 
実行結果は以下の通りである:(行番号XXを前に付けた)#01 Declaration[int vInt=10]type==int#02 Declaration[arr[2]={10,20}]type==int*#03 Declaration[int*p=&vInt]type==int*#04 Declaration[int**p 2 p=&p]type==int*#05 Declaration[int]==={&vInt,&vInt}]type==**06 Declaration[int(**p 2 arr)[2]=&arty[2]=&arty] pe==int(*)[2]
結果を分析してみましょう.私たちはすでに第1部の基本的な知識を持っているので、私たちが宣言したタイプを明確に区別することができます.ここには主に2つの重要な部分がありますが、コンパイラがどのように実現されるかの原理はここで議論されていません.
------#02:配列---------
今#02を見て、何か考えましたか?コンパイラから見れば、配列は対応するタイプのポインタタイプにすぎません.配列を関数に渡すとポインタが渡されるので,パラメータを用いて配列要素を修正することができる.この変換はコンパイラが自動的に完了します.
void f(int[]); int a[2]={10,20}; f(a);//この行はコンパイラが完了した関数変換f(int*p)に等しい
つまり、ここでコンパイラはint[]タイプからint*への変換を自動的に完了し、コンパイラが完了したことに注意し、言語自体が実現したとも言えるので、私たちはこれを受け入れるしかありません.
------#05:ポインタ配列----------
ポインタ配列のコンパイラ内部表示も対応するタイプのポインタです.
-------#06:配列ポインタ---------------------配列ポインタのコンパイラ内部表示はちょっと特別です.コンパイラ(あるいは言語自体)には配列ポインタという内部表現があります.c++言語のタイプが厳格にチェックされている言語(もちろん暗黙的なタイプ変換があるものもあります)
だから私たちの次の書き方はコンパイルできません.{file://---------編む訳で-----------int arr[3]={10,20};//注意は3つの要素配列int(*p 2 arr)[2]=&arr;//注意2つの要素配列を指すポインタfile://---------編むは、----}
################################################################################
上の2つのセクションの内容を通じて、配列、ポインタ、ポインタ配列、配列ポインタはいったいどのようにして一度のことなのか、基本的に理解しているでしょう.
--------補足開始------------------------配列とポインタの変換、およびポインタ(++,-)などを使用して配列を操作するのは、配列に基づいてメモリに連続的に分布しています.
しかし、私たちが「反復器」を使うとき、状況は違います.この問題は本文では論じない.
--------補足終了----------------------
しかし、c++言語自体には奇妙な点がたくさんあります(c++はc言語や古いc++バージョンと互換性があることを考慮しなければならないからです).組み込みタイプのこれらの性質の特徴は、関数部分に少し変化することがありますが、コンパイラが何をしたかを知っていれば、あまりおかしくありません.しかし、関数部分の内容については次回にします.
今、上の内容に戻ります.ここではやはり内装のタイプについてお話しします.明らかに同じタイプの変数は互いに値を割り当てることができる.しかし、タイプの広がり、クラスの継承システムの問題など、他にも可能な場合があります.
もちろん、異なるタイプは一般的に互いに値を割り当てることができません.もちろん、ここの例外は強制転化、クラスの継承システムなどです.
ここを見ると、次のプログラムがなぜ実行されているのかがわかります.ここでも以下の手順を今日の内容のまとめとしています.
#include <iostream>
using namespace std;
int main()
{
 int a[2]={10,20};
 int *p=a;//      ,        ,         
 
 int vInt=10;
 int *parr[2]={&vInt,&vInt}; 
 int **p2p=parr;//    ,    
 
 return 0;
}

 
From:http://www.chinaitpower.com/A/2001-10-17/2030.html