配列はポインタ、サンプルコード


 前章に関しては、サンプルコードを作る予定では無かったのですが、インクリメント演算子等の解説もしたかったし、文字列の説明をする上でも、この段階でアドレスを引数として受け取った関数内でのポインタの扱い方も知っておいた方がいいと思ったので、予定を変更してサンプルコードを載せます。前章でのサンプルコードは配列の扱い方でしたが、今度はもう少し実用的です。同じく、配列を間接演算子とインデックス番号を用いて表す方法と、2つとも使わない方法を示します。

 ここの、サンプルコードでの要求仕様は配列のアドレスを関数の引数として渡し、戻り値にその合計を返すという物です。配列の数は不定としたいので、計算したい配列の個数も引数として渡すことにします。(アドレスを受け取った方の関数では、その配列の個数が分からない!!)

 つぎに、インクリメント演算子について、簡単に説明します。例えば、while 等のループ内でその、ループ回数をカウントしたいとき、変数 i に対して、

i = i + 1;
と表すと思いますが、これは、次のようにも表す事が出来ます。
i++;
この、"++" をインクリメント演算子といい、他の言語には無いようですが、C言語ではよく用います(私は)。逆のデクリメント演算子 "--" なんてのもあります。処理的にマイナスのカウントというのは素直な考え方ではないので、あまり見かけませんが・・・。考え方は同じです。1引かれるだけです。

 この、インクリメント演算子(又はデクリメント演算子)はポインタに対しても使うことが出来ます。例えば、

char* buf;
buf++;
とした場合、ポインタの指す位置が次のアドレスになります。(注:上の2文だけを main の中に入れてコンパイル、実行するとハングします、多分・・・。)つまり、ポインタが進むわけです、次のアドレスに。どれだけ進むか(何バイト進むか)はインクリメントしたポインタ型によります。char 型であれば、1バイト、int 型であれば2バイト(マイクロソフト系コンパイラ)です。これはコンパイラによって違いますが、要するに、そのデータサイズ分、ポインタが進むわけです。何バイト進めたいかはプログラムの方でやってくれるので気にすることはありません。分かりにくいですか?

 では、実際にプログラムです。computeSum1、computeSum2 の2つの関数は書き方こそ違いますが、同じ処理をしています。

サンプルコード
<配列を使う(配列はポインタ、サンプルコード)>
ソースファイル(0.7K-Byte)
------------------------------ sample4.c START ------------------------------
    #include
    
    int computeSum1( int* data, int count )
    {
      int i;   /* ループカウンタ */
      int buf;  /* 計算結果 */
    
      buf = 0;  /* 初期化 */
    
      /* 合計の計算 */
      for ( i = 0; i < count; i++ ){
        buf = buf + data[i];
      }
    
      /* 戻り値 */
      return buf;
    }
    
    int computeSum2( int* data, int count )
    {
      int i;   /* ループカウンタ */
      int buf;  /* 計算結果 */
    
      buf = 0;  /* 初期化 */
    
      /* 合計の計算 */
      for ( i = 0; i < count; i++ ){
        buf = buf + *data;
        data++; /* アドレスのインクリメント */
      }
    
      /* 戻り値 */
      return buf;
    }
    
    main()
    {
      int data[5];  /* データ */
      int ret;    /* 関数戻り値 */
    
      /* 計算するデータの設定 */
      data[0] = 10;
      data[1] = 20;
      data[2] = 30;
      data[3] = 40;
      data[4] = 50;
    
      /* 合計の計算 */
      ret = computeSum1( data, 5 );
    
      /* 計算結果の画面出力 */
      printf( "computeSum1 result = %d\n", ret );
    
      /* 合計の計算 */
      ret = computeSum2( data, 5 );
    
      /* 計算結果の画面出力 */
      printf( "computeSum2 result = %d\n", ret );
    
      return 1;  /* お約束(^m^) */
    }
------------------------------ sample4.c END ------------------------------

 合点してもらえたでしょうか?

data++;
の一文で、ポインタの指すアドレスを次の配列要素を指すようにしています。

 余談ですが、先にポインタを使う利点を挙げました。conputeSum 関数は5つの配列のデータを受け取ったことになりますが、実際は先頭のアドレスを受け取っただけです。受け取るデータのサイズが大きくなればなるほど、データコピーに要するオーバーヘッドをポインタによるデータの受け渡しで軽減していることが、ここで分かります。オーバーヘッドの差なんて、数ミリ秒なんでしょうけど・・・。ループなどで何回も繰り返す場合はその差が出てくると思われます。

 配列はその変数の宣言によって連続したメモリ空間を取得します。というか、取得されると言った方がいいでしょうか。char buf[10]; と宣言すると、コンピュータのメモリ上の連続した空間に10バイトのメモリが割り当てられます。「連続した」ってのが肝腎で、アドレスのインクリメントで配列の次のデータが順に参照できるのはこのためです。後に構造体の話もしますが、構造体も連続したメモリ空間に割り当てられます。覚えておいて下さい。


文字列を扱う前に

C言語講座トップページ

TOP-PAGE

Web-Page制作者e-mailアドレス