ポインタと配列

5月18、2009年で掲示される+のC / C +

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

想起配列

配列、またはマトリックス、または配置、数学的抽象化、同種のデータのセットを、同じ型(int型、などのフロートすなわち表すために使用)です。 この抽象化は、表形式で、行や列で構成されます。 行列の各要素はユニークなている(行と列)、座標ように指定された要素のメール(私は、j)は"行i'は、'列j"の唯一の要素を表します。

次のように宣言配列の構文は:

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

 / / 2次元配列
 2 ] [ 3 ] ; // 2 linhas (0 a 1) e 3 colunas (0 a 2) IMAT intは )[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 ] ; IMAT intは ] [3] [4;

 / /イベットのベクトルの要素を変更する4。
 / /要素ことを忘れないでゼロからカウントを開始する
 ] = 13 ;イベット[3] = 13;

 / /イベットのベクトルの要素を2番目の読書
 ivet [ 1 ] ; int型の numは=イベット[1];

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

 / / IMAT 3番目の読書の要素を行、列の4番目、
 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 のchar [13];
 20 ] ; dvet ダブル [20];

 3 ] [ 4 ] ; CMAT のchar [3] [4];
 5 ] [ 4 ] ; IMAT intは ] [5] [4;

 "sizeof(int)     = " << sizeof ( int ) << endl ; 裁判所 <は ヒノキ 未満)<<"ははsizeof(int  )="<<sizeof(int  
 "sizeof(char)    = " << sizeof ( char ) << endl ; 裁判所 <"は未満はsizeof(char)="<< sizeof(char)<< のヒノキ。
 "sizeof(double)  = " << sizeof ( double ) << endl ; 裁判所 <"は未満はsizeof(ダブル )="<<sizeof演算 (ダブル)<< のヒノキ。

 "sizeof(ivet)    = " << sizeof ( ivet ) << endl ; 裁判所 <"は未満はsizeof(イベット )="<<sizeof演算 (イベット )<<ヒノキ。
 "sizeof(cvet)    = " << sizeof ( cvet ) << endl ; 裁判所 <"は未満はsizeof(Cvet)="<<sizeof 演算 (Cvet)<<ヒノキ。
 "sizeof(dvet)    = " << sizeof ( dvet ) << endl ; 裁判所 <は ヒノキ未満)<<" はsizeof(dvet  )="<<sizeof演算 (dvet;
 "sizeof(cmat)    = " << sizeof ( cmat ) << endl ; 裁判所 <"は未満はsizeof(CMAT)="<<sizeof 演算 (CMAT)<<ヒノキ。
 "sizeof(imat)    = " << sizeof ( imat ) << endl ; 裁判所 <"は未満はsizeof(IMAT)="<<sizeof 演算 (IMAT)<<ヒノキ。 

結果は非常に合理的です。 スペースは行列が占有する要素の要素のタイプ(行のサイズx列を掛けた数に等しいのXはsizeof(型))。 各要素は独立している場合は、それは、それぞれが、それ以降は1別の要素が上書きされますメモリ内の別の場所を占めていると見なされます。 そこで、各要素は、独自のメモリアドレスを持っている?

配列とメモリアドレス

便宜のために、我々は、文字のサイズが1バイトしか与えられて配列を、可能なアドレスを分析する:

  15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
  5 ; const intに最大= 5;
 max ] = { 'A' , 'B' , 'C' , 'D' , 'E' } ; Cvet にchar [最大] =('A'は、'B' を、'C'を、'D'と、'メール');

 / /内容を表示、データの値とアドレス。
 "Índice \t Valor \t Endereço do elemento \n " ) ;  printf("インデックス \ tを適正\トンの要素アドレス\ n");
 int i = 0 ; i < max ; i ++ ) { 0 = するfor(int私は私が<最大;+ +)(
     "%d \t %c \t %p \n " , i, cvet [ i ] , & cvet [ i ] ) ;  printf("%d個の \トン%cは%\トンの%p \ n"の、は、Cvet [i]は、&Cvet [i]を);
 

 アドレスの配列を表示します/ /
 "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. 28行に示すように、非常に変数Cvetはポインタとして解釈することができます。

C + +では、一般的な配列の名前(キャスト解釈できるメモリの連続ブロック)へのポインタとして、その最初の要素を指します。 また、それが有効な宛先へのポインタは、配列の要素の型と同じ型の配列へのポインタをポイントすることです。 ポインタに配列のatrubuição中に、コンパイラは暗黙の型変換を行います。 先のポインタがメモリ領域の配列によって占有さへのポインタとして解釈される。

1つは、結果はそれほど明白なのですが暗黙のキャストは、その領域は、メモリアレイされた情報を失ったことができない。 したがって、配列のサイズに関する情報が失われます。 ポインタの観点から、それはメモリの任意のブロックのサイズも任意の先頭を指している。 終了し、配列内のポインタへの抽象化から、よりに、より高レベルの抽象化制限行くこと少なく、低レベルの制限。

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

  15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
  300 ; const intに最大= 300;
 max ] ; Cvet にchar [最大];
 pc = 0 ; char * 文字のPC = 0;

 " \n Antes da atribuição \n " ) ;  printf("  \ n代入する\ 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( パソコン));

パソコン= Cvet;

 " \n Depois da atribuição \n " ) ;  printf("  \ n代入する\ 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( パソコン)); 

注:その前に代入(25行)ポインタのPC。 それはそう起動してからはnullです。 既にサイズが、その配列は300バイト、ポインタをわずか8(私のマシンを示す、64)は、AMD。 代入の後、両方のメモリの同じ領域には"ポイント"を渡すのサイズは変更しないでください。 このエリアへのポインタとchar *を、ゲームにした暗黙300] [キャストにchar型のメモリのサイズを知っているPCのことはできません指すそれが。 しかし、配列Cvet はまだ危機を知るまさに存在せず、彼がいる。

ポインタ演算 - Vulgoので、何ですか?

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

  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 ; const intに最大= 6; 
 max ] = { 'B' , 'L' , 'A' , 'B' , 'O' , 'S' } ; Cvet にchar [最大] =('B'を、'L' は、'A'は、'B'を、'O'を、'S'に);

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

 int i = 0 ; i < max ; i ++ ) { 0 = するfor(int私は私が<最大;+ +)(
     "%c" , * ( pc + i ) ) ;  printf("%c"*(パソコン + 1));
 
 " \n " ) ;  printf("する\ n");

 int i = 0 ; i < max ; i ++ ) { 0 = するfor(int私は私が<最大;+ +)(
     "%c" , * pc ++ ) ;  printf("%c "*パソコン+ +);
 
 " \n " ) ;  printf("する\ n");


 /ここで、整数/
 max ] = { 1 , 2 , 3 , 4 , 5 , 6 } ;イベット int [最大] =(1、2、3、4、5、6);
 pi = ivet ; int型 *π= イベット;

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

 で2次元/ /
 2 ] [ 3 ] = { { 'B' , 'L' , 'A' } , { 'B' , 'O' , 'S' } } ; CMAT のchar [2] [3] =(('B'を、'L' 、'A'は)、('B'を、'O'、'S'に));
 ppc ; char *は ppcの。

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

 int i = 0 ; i < 2 ; i ++ ) { 0 = するfor(int私は私は<2;+ +)(
     int j = 0 ; j < 3 ; j ++ ) { 0 = するfor(int jは、j<3 jは + +)(
         "%c" , * ( ppc + 3 * i + j ) ) ;  printf("%c"*(3 ppcの + * iの+ jの));
     
     " \n " ) ;  printf("する\ n");
 
 " \n " ) ;  printf("する\ n"); 

パソコンでは18行ポインタ 、配列今ポイントにCvetと文字 '結果への最初の要素、B'を。 21行目ではPCのそれは文字を'格納されたアドレスです内容、B'を、すなわち、次にド参照増加します。 それが逆参照値を'B'のですので、最初のiの値を渡すゼロです。 次の手順では、次のアドレスはドは他の文字、元の配列に格納され参照されている。 これは、多かれ少なかれは何コンパイラが内部的にするときには、構文Cvet [i]を使用していません。 の配列の抽象化)ができますパソコン+私*そのメモリ領域の連続でより多くの友好的な方法をのディーリングあなた。

しかし、配列の抽象化は、ポインタ演算を使用するより簡単ですか?

1つの答えは26行です。 彼女が、少し速く21行目と同じことをしません。 任意のデータを21行、または同様の構文では、配列構文、アクセスすることができます約もコマンドで要約:

  1. 配列のベースアドレスを取ること。
  2. インデックスの値に対応する追加します。
  3. デ-参照新しいアドレスを。

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

  1. デ-参照、このアドレスを。

とアドレス)がないと言うが、それはその理由の一部+ +私が作ったアカウントまたは(コマンドインクリメントのループが、+ bの=がより速く℃;。 今66%のこの小さな利得を1 MBのデータ領域に適用されると思う。 が200万のコマンドを以下以上になるでしょう!

のメモリ領域を任意のハンドルへのポインタを使用し手法の一つである操作を一般的に使用される低レベルに近いプログラミング(マシン)バッファ汚い手口や他の文字列のうち、。 コンピュータの腸では、操作がメモリの掃引大きな領域は、しばしば、ポインタ演算で実行されます。 レベルでは、この、 ダーウィンは生き残る最高支配とは、最もれる準備。 ここでは言語は、投稿者の力が唯一の心の純粋な理解できる与えることから始まります。

重要な注意は、その境界線31と38の経験整数で繰り返されます。 自動的にはsizeof(型)計算の整数が4バイトとして、インクリメントは自動的に1が1日、4 4バイトを、作られていますインクリメントすなわち注意してください。 ポインタをインクリメントするメモリの次の領域を実際のデータだけでなく、次のアドレスに似てアクセスを意味します。 の大きさとしてchar型1バイト、incremetamosポインタはcharへ、1バイトだけを移動されます。 場合は、インクリメントポインタを2倍に、我々は、8バイトを移動しように。

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

ボイド*、性表現が多様ポインタ

以前の私はそれだけで、同じタイプのされたポインタに配列を割り当てると述べたその配列データ。 私は露骨にうそ! その理由は、このトピックの前にポストを辞任した人は、それは彼がすることはできません信じるように安全である :)

この規則に2つの例外があります。 ""その権利の種類を指していると考えている最初のあるときは明示的な型変換、ポインタのターゲットです。 例では、上記のコードの44行です。

2番目のポインタの場合無効にすることです。 ポインタが無効にデータのメモリ領域に型には需要を作るのポインタですそれが指す。 彼は、メモリの一般的な領域は、何か非常に低いレベルへのポインタです。

ドはに参照データを使用するには、ポインタによる事前のデ参照してください無効にすると指摘、我々は有効な型にintは*の場合は、のデはint型とchar *を参照明示的なキャストを行う必要がありますchar型、それは何デはvoid *を参照していると思う?

  15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
  6 ; const intに最大= 6; 
 max ] = { 'B' , 'L' , 'A' , 'B' , 'O' , 'S' } ; Cvet にchar [最大] =('B'を、'L' は、'A'は、'B'を、'O'を、'S'に);

 pv = cvet ; ボイド * pvを= Cvet;

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

 int i = 0 ; i < max ; i ++ ) { 0 = するfor(int私は私が<最大;+ +)(
     "%c" , * ( ( ( char * ) pv ) + i ) ) ;  printf("%c"*(((char *)を pvを)+ 1));
 
 " \n " ) ;  printf("する\ n"); 

ポインタは、1つは、メモリの一般的な領域へのデータは、このエリアには、含まれているかなど、そのパラメータ、の種類について仮定することができる機能の種類/知識コントロールをせずにポイントする必要が使用され無効にするAPIのlibにpthreadの (任意のリンク)。

閉じる

さらに我々は、ポインタのトピックを詳細に調べる、我々は近いマシンに。 多くのCやC + +の派生そこの力と、多くの問題も。 複雑さは、あまりにもリスクが高まっている。 多くのそこに楽しみがあるの!

リンク

コメント

    ディスカスブログによって供給コメント