わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

関数から見た配列のサイズは?

昨日の続きです.
関数が配列を受け取るときには,配列のサイズ(要素数)をどうやって獲得するか,ちょっと配慮しないといけません.というのも,「関数が配列を受け取る」とき,その仮引数は,常にポインタになるからです.「void selection_sort(int array[6])」と書いても,arrayはポインタ変数です.
さてarrayが配列変数なら,sizeof(array) / sizeof(array[0])によってその要素数を求められます*1が,arrayがポインタ変数ではできません.関数の仮引数に限らず,int *array;のとき,sizeof(array) / sizeof(array[0])は,sizeof(int *) / sizeof(int)として計算されます.
関数が,参照渡しで配列を受け取るときに,その要素数を獲得する方法には,次の3通りが考えられます.状況によって,いずれか一つを選ぶといいでしょう.

  • 配列の要素数を,定数として定義します.この定数は,関数からも呼び出し元からも共通に参照できるものとします.処理対象の配列の要素数が固定のとき,これを使うとよいでしょう.
#define ARRAY_SIZE 6
…
void selection_sort(int *array)
{
  /* 配列の要素数は ARRAY_SIZE */
}
…
  int array[ARRAY_SIZE] = {3, 1, 4, 5, 9, 2};
  selection_sort(array);
  • 配列の要素数も,引数として関数に渡します.配列の要素数が,関数呼び出しごとに変わり得るとき,これを使いましょう.
void selection_sort(int *array, int size)
{
  /* 配列の要素数は size */
}
…
  int array[] = {3, 1, 4, 5, 9, 2};
  selection_sort(array, sizeof(array) / sizeof(array[0]));
  • 配列の末尾に,番兵を置きます.配列の途中に意図的に番兵を置くこともできます.ただし個人的には,この書き方はお勧めしません.というのも,上述の「配列の要素数も引数として渡す」ほうが優れているからです.人のコードを読んでいて,配列の末尾が0だったり負だったり,文字列の配列ならNULLだったりしたときに,番兵かなと思ってください.
#define ARRAY_SIZE 6
…
void selection_sort(int *array)
{
  /* 配列の要素数は,番兵から求める */
}
…
  int array[ARRAY_SIZE] = {3, 1, 4, 5, 9, 2, -1};
  selection_sort(array);

*1:関数の中のローカル変数として配列を定義する場合にも,この式で求められます.