ポインタと配列

2009年5月18日- Ĉで掲示される/ C + +の

このシリーズの最初の記事では、 ポインタを少し話す 2番目では、 参照の話 今日、我々の親密な関係に(UIを!)ポインタと配列(または配列の間)がフォーカスされます。

想起配列

配列、または配列、または配列は、数学的抽象化、均質なデータのセットを表すためには、同じタイプつまり、使用されて(、、などのフロート)int。 この抽象化を表形式で、行や列で構成されます。 配列内の各要素は(行、列)座標ように、特定の要素E(私は、j)のi"はの"J列は、"行の唯一の要素を表しています。

宣言配列の構文は以下のとおり:

  / / 1次元配列またはベクトル
 10 ] ; // 10 elementos, do 0 ao 9イベットint [10] / / 10の要素を、0〜9
 23 ] ; // 23 elementos, do 0 ao 22 0から22日まで cvet 文字 [23] / / 23の要素

 / / 2次元マトリクス
 2 ] [ 3 ] ; // 2 linhas (0 a 1) e 3 colunas (0 a 2) int imat [2] [3] / / 2行(0から1)、3列(0〜2)
 10 ] [ 2 ] ; // 10 linhas (0 a 9) e 2 colunas (0 a 1) DMAT ダブル [10] [2] / / 10行(0〜9)および2列(0〜1) 

配列の各要素は、他の独立しており、次の構文のようにアクセスすることができます:

  10 ] ;イベットint [10];
 3 ] [ 4 ] ; int imat [3] [4];

 / /ベクトルイベットの4番目の要素を変更する。
 / /はゼロ要素から実行を開始する記憶
 ] = 13 ;イベット[3] = 13;

 / /ベクトルイベットの2番目の要素レディング
 ivet [ 1 ] ; intテンキー=イベット[1];

 / / 2番目の列imat最初の行の要素を変更する
 ] [ 1 ] = 42 ; imat [0] [1] = 42;

 / / 4列目imat 3行目の要素レディング
 imat [ 2 ] [ 3 ] ; intはFoo = imat [2] [3]; 

この記事では我々は、我々は非常に直観的に配列とポインタとの間の関係を調べる背景行列については説明しません。

サイズ配列

以来、配列には、同じ型の複数の値は、どれだけ含まれて抽象化したものは何ですか? どのようにメモリを占めて多くのスペース?

以下のコードを考えます:

  17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
  10 ] ;イベットint [10];
 13 ] ; cvet 文字 [13];
 20 ] ; ダブル dvet [20];

 3 ] [ 4 ] ; CMAT 文字 [3] [4];
 5 ] [ 4 ] ; int imat [5] [4];

 "sizeof(int)     = " << sizeof ( int ) << endl ; 裁判所は """sizeof(INT) ="""sizeof(INT) ""endl;
 "sizeof(char)    = " << sizeof ( char ) << endl ; 裁判所は """sizeof(文字 )="""sizeof(文字 )""endl;
 "sizeof(double)  = " << sizeof ( double ) << endl ; 裁判所は """sizeof()="""sizeof(ダブル )""endl ダブル ;

 "sizeof(ivet)    = " << sizeof ( ivet ) << endl ; 裁判所は """sizeof(イベット)="""sizeof( イベット)""endl;
 "sizeof(cvet)    = " << sizeof ( cvet ) << endl ; 裁判所は"""sizeof(cvet)="""sizeof(cvet)""endl;
 "sizeof(dvet)    = " << sizeof ( dvet ) << endl ; 裁判所は"""sizeof(dvet)="""sizeof(dvet)""endl;
 "sizeof(cmat)    = " << sizeof ( cmat ) << endl ; 裁判所は"""sizeof(CMAT)="""sizeof(CMAT)""endl;
 "sizeof(imat)    = " << sizeof ( imat ) << endl ; 裁判所は"""sizeof(imat)="""sizeof(imat)""endl; 

その結果、非常に合理的です。 スペースの配列によって占領さの要素の要素の型のサイズを掛けたの数(行x列と等しいはx sizeof(型))。 ただし、各要素は独立して、それはそれぞれ、そうでなければ1つの別の要素を上書きされるメモリ内の別の場所を占めるものとみなされます。 そのためには、各要素は、その独自のメモリアドレスは何ですか?

配列とメモリアドレス

便宜のために、私たちを唯一の1バイトで指定され、文字の配列、そのサイズは、可能なアドレスを分析する:

  15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
  5 ; ポーラint最大= 5;
 max ] = { 'A' , 'B' , 'C' , 'D' , 'E' } ; cvet 文字 [最大] =(''、'B' を'、'C'を'、'開発'、'E'の);

 / /の内容を、値、およびデータのアドレスを表示する。
 "Índice \t Valor \t Endereço do elemento \n " ) ; printfの ("目次\ t\トンの要素住所\ n");
 int i = 0 ; i < max ; i ++ ) { (int = 0;私は"最大 のため + +)(
     "%d \t %c \t %p \n " , i, cvet [ i ] , & cvet [ i ] ) ; printfの ("%d\トン%はC \トンが%p \ N"は、私、cvet [私]、&cvet [私]);
 

 / /印刷の配列のアドレス
 "Endereço da matriz: %p \n " , & cvet ) ; 配列 、printf("住所:%pを\ N"は、&cvet);

 / /印刷の配列のアドレスを再度
 "Endereço da matriz: %p \n " , cvet ) ; 配列 、printf("住所:%pを\ N"は、cvet); 

の要素のアドレス、つまり、各要素が格納されて元の横に連続している。 また、2つ以上の興味深い事実である:

  1. 配列(&cvet)、ライン25で示されるアドレスは、配列の最初の要素と同じです。
  2. 非常に変数cvetポインタとしてとして、28行目に示すように解釈することができます。

C + +では、共通の配列の名前へのポインタとして(鋳造)が解釈することができますメモリの連続ブロックされ、その最初の要素をポイントします。 さらにこれは、配列へのポインタをポイントすることは有効ですが、宛先へのポインタは、配列の要素の型と同じ型です。 へのポインタの配列atrubuição時には、コンパイラの暗黙の型変換ができます。 先のポインタは、メモリ領域は、配列が占有するのポインタとして解釈されることです。

1つは、結果は明白ではないのでは、暗黙的なキャスト時に、そのエリアには、メモリアレイされた情報は失われます。 したがって、配列の大きさの情報が失われます。 ポインタの観点からは、メモリの任意のブロックサイズの先頭にも任意のを指している。 配列をチェックし、ポインタへの抽象化はますます高い制限レベルの抽象化からなることを意味以下と低いレベルの制限。

一方、配列へのポインタを割り当てようとすると互換性のないタイプのコンパイルエラーを生成します。 としてのポインタは1つだけ入力、アドレスを持つ配列をn個のデータ(バイト)のメモリブロックです。 コンパイラは、事前に知ることができないかどうかのポインタを1点、2〜200の領域にバイトです。

  15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
  300 ; ポーラint最大= 300;
 max ] ; cvet 文字 [最大];
 pc = 0 ; 文字 *パソコン= 0;

 " \n Antes da atribuição \n " ) ; 代入の前に printfの ("\ Nの\ Ñ");
 "cvet = %p \n " , cvet ) ; printfの ("cvet =%pの\ N"は、cvet);
 "pc   = %p \n " , pc ) ; printfの ("パソコン=%pの\ N"は、 パソコン);
 "sizeof(cvet) = %lu \n " , sizeof ( cvet ) ) ; printfの ("sizeof(cvet)=%lu\ Nで"、sizeof(cvet));
 "sizeof(pc)   = %lu \n " , sizeof ( pc ) ) ; printfの ("sizeof()=%lu\ Nで"、sizeof( パソコン)) PC;

パソコン= cvet;

 " \n Depois da atribuição \n " ) ; printfの ("\ n代入の後\ Ñ");
 "cvet = %p \n " , cvet ) ; printfの ("cvet =%pの\ N"は、cvet);
 "pc   = %p \n " , pc ) ; printfの ("パソコン=%pの\ N"は、 パソコン);
 "sizeof(cvet) = %lu \n " , sizeof ( cvet ) ) ; printfの ("sizeof(cvet)=%lu\ Nで"、sizeof(cvet));
 "sizeof(pc)   = %lu \n " , sizeof ( pc ) ) ; printfの ("sizeof()=%lu\ Nで"、sizeof( パソコン)) PC; 

注意する前に、代入(25行目)は、ポインタのPC。 nullですので、初期化されました。 以来の大きさは、配列の300バイトとポインタは8日(私のマシンを示すamdの64)です。 代入の後、両方のメモリの同じ領域には、しかし、"ポイント"を渡すとサイズを変更しないでください。 あるchar型に暗黙的なキャスト[300] char *には、そのゲームのPC内のポインタが指すメモリ領域のサイズを知ることはできませんでした。 配列を正確に、彼は実存主義の危機なしに知ってcvet続けて以来。

ポインタ演算 - 俗ので、何?

理由は、もし私は、配列内のデータが並んで配置されて知って、私は次のアドレスにジャンプし、次の要素にアクセスするポインタを使用することができます。 この演算へのポインタであるの名前。

  15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
  6 ; ポーラint最大= 6; 
 max ] = { 'B' , 'L' , 'A' , 'B' , 'O' , 'S' } ; cvet 文字 [最大] =('B' を'L'は、''、'B'を'、'O'にの'S');

 pc = cvet ; 文字 *パソコン= cvet;

 int i = 0 ; i < max ; i ++ ) { (int = 0;私は"最大 のため + +)(
     "%c" , * ( pc + i ) ) ; printfの ("%c"、*( パソコン + 1));
 
 " \n " ) ; printfの ("\ Ñ");

 int i = 0 ; i < max ; i ++ ) { (int = 0;私は"最大 のため + +)(
     "%c" , * pc ++ ) ; printfの ("%c"、*パソコン+ +);
 
 " \n " ) ; printfの ("\ Ñ");


 / /ここで全体の
 max ] = { 1 , 2 , 3 , 4 , 5 , 6 } ;イベットint [最大] =(1、2、3、4、5、6);
 pi = ivet ; int *パイ= イベット;

 int i = 0 ; i < max ; i ++ ) { (int = 0;私は"最大 のため + +)(
     "%p = %d \n " , pi, * pi ++ ) ; printfの ("が%p =%d個\ N"は、π、π* + +);
 
 " \n " ) ; printfの ("\ Ñ");

 / / 2つのディメンションでは
 2 ] [ 3 ] = { { 'B' , 'L' , 'A' } , { 'B' , 'O' , 'S' } } ; CMAT 文字 [2] [3] =(('B' を'L'は、'')、('B'を'、'O'にの'S'));
 ppc ; 文字 * ppcの;

 char * ) cmat ; ppcの=( *)CMAT;

 int i = 0 ; i < 2 ; i ++ ) { (int = 0;私は"2;+ +)(
     int j = 0 ; j < 3 ; j ++ ) { (int論文= 0、"3 論文 + jに対して+)(
         "%c" , * ( ppc + 3 * i + j ) ) ; printfの ("%c"、*(ppc  + 3 * iの+ j)は);
     
     " \n " ) ; printfの ("\ Ñ");
 
 " \n " ) ; printfの ("\ Ñ"); 

18行目のポインタをパソコンでは現在、配列cvetをポイントし、したがって、その最初の要素は、文字'にはB'。 21行目の上のPCは、アドレスをここでは、'B'を、すなわちに格納されている内容は、次にド参照インクリメントされます。 最初の1週間ではiの値がゼロの場合、値は'するので、間接参照はB'。 以下では、次のアドレスデ他の文字は、元の配列に格納され、参照されている。 それよりかは、コンパイラ内部でするときに[iは構文cvetを使用するものが少ない]。 配列の抽象化するメモリは、*(パソコン+ iの連続した領域を扱うのは、よりわかりやすい方法を提供します

しかし、配列の抽象化を簡単にされると、ポインタ演算を使用する?

答えは1つの行は26です。 彼女は同じことをやっては、21行目が、少し速くなります。 21行目、または同様の構文では、配列構文を、任意の情報へのアクセスは非常にコマンドでラフにまとめることができます:

  1. 配列のベースアドレスを取得;
  2. インデックスの値をアドレスに追加する;
  3. ドを参照し、新しいアドレス;

既にポインタ演算では、このようになります:

  1. ドを参照し、このアドレス;

このコマンドは、インクリメント(またはアドレスに関しては)これは、ループの一部であるとしてカウントされません、 + +; = bよりも高速です+ Cを行った;。 現在66%のこの小さな利得は、1 MBのデータ領域に適用されると思う。 が200万人以上のコマンドを以下になります!

メモリの任意の領域を処理するためのポインタを使用して技術を一般的に低レベルのプログラミングでは、マシン(に近い)には、 バッファと文字列の操作は、他の汚い手の間で使用されます。 コンピュータの腸では、操作がメモリの掃引大きな領域は、しばしば、ポインタ演算が実行されます。 このレベルでは、 ダーウィンと最高君臨だけが生き残る用意しました。 言語ここからは力が唯一の心の純粋な理解することができますを与えることから始まります。

重要な注意されている間に線を31日と38の経験を整数で繰り返されます。 として、整数は4バイトですが、単位を自動的にインクリメントすなわち、4バイトではなく、1対1の作られています注意してください自動的にsizeof(型)が計算されます。 ポインタを強化するメモリは、実際のデータだけでなく、次のアドレスに似て、次のエリアへのアクセスを意味します。 char型のサイズとしてときにはcharへのポインタが1バイトのみを移動incremetamos 1バイトです。 もしdoubleへのポインタを増進させるため、我々は、これは8バイトに移動します。

もう1つの観測が2つ、2次元配列"52行40に示すように線形化された"ことができます。 これは、該当する場合、プロセッサのキャッシュをより有効に活用するのに便利です。たとえば、。

無効*、 表現が多様なポインタ

以前の私だけでは、配列データと同じ型だったのポインタに配列を代入することが可能だった。 私は露骨にうそ! その理由は、人は、このトピックの前にポストをあきらめた人は、それができると信じてする方が安全です :)

この規則に2つの例外があります。 最初にある場合の種類とポインタをターゲットの明示的な変換です""それは、適切な種類を指していると考えています。 例では、前述のコードの44行でいます。

2番目のポインタを無効にした場合です。 voidへのポインタは、データはそれが指すメモリ領域にされているタイプには要求になるのポインタです。 彼は、ポインタをプラメモリの一般的な事項、何か非常に低いレベルです。

すべての情報を利用するには、ポインタによる事前の統計はvoidへの参照を指摘した場合は、有効な型を明示的にキャストする必要があります、それ* 06 - intと* 06がChar -を基準に参照されるintですchar型、何が06だと思います-はvoid *を参照?

  15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
  6 ; ポーラint最大= 6; 
 max ] = { 'B' , 'L' , 'A' , 'B' , 'O' , 'S' } ; cvet 文字 [最大] =('B' を'L'は、''、'B'を'、'O'にの'S');

 pv = cvet ; 無効 *太陽光発電= cvet;

 / /エラーをコンパイルします。
 / / *太陽光発電
 / /どのくらいのsizeof(無効)ですか?

 int i = 0 ; i < max ; i ++ ) { (int = 0;私は"最大 のため + +)(
     "%c" , * ( ( ( char * ) pv ) + i ) ) ; printfの ("%c" 、*(((文字 *)太陽光発電)+ 1));
 
 " \n " ) ; printfの ("\ Ñ"); 

ポインタを使用されるときに1つのメモリの一般的な事項を制御することなく、ポイントする必要があります/この領域に含まれるデータ、または関数の型の知識など、そのパラメータの種類について仮定することはできませんを無効にAPIのlibにpthreadsを (任意のリンク)。

閉会

さらに我々掘り下げポインタ上のトピックには、マシンの我々の横にある。 多くのCやCのパワーの+ +はそこからやって来て、問題だけでなく、多くの。 複雑さとリスクも高まっている。 多くの人にとって、そこに楽しみにある!

リンク

コメント

1つの応答"ポインタと配列に

  1. レアンドロメロ 2009年5月21日21:50

    よく教則。 私は、"表現が多様なポインタが好きだった。 :)

返信コメントを残す




WPのHashCashので電源