Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

C/C++で配列の長さの求め方

スポンサードリンク

f:id:fa11enprince:20200628232714j:plain
C/C++で配列の長さの求め方です。
超基本中の基本なのですが、しばらくC/C++の配列を使っていないと
アレレってことになってしまいます。
今日はそれでハマりました。
sizeofを使って配列の長さ(要素数)を求めたはずが、
なんでか落ちる…バッファオーバーランっぽい。
こんなコードです。

int hoge[20];
for (int i = 0; i < sizeof(hoge); i++)
{
    hoge[i] = 0;   // バッファオーバーランしちゃうよーぎえー(´・ω・`)
}

memset()使えよとかそういう問題ではありません。
ちなみに、次のパターンなら通常の環境の場合バッファオーバーランにはなりません

char hoge[20];
for (int i = 0; i < sizeof(hoge); i++)
{
    hoge[i] = 0;   // おっけー!一応ね…
}

そうです。char型の場合だと1バイトなので割る必要はないですが、
int型だと1つあたり4byteなので(環境依存ですが……)一つあたりの型の長さの分で
割ってやらなければいけません。

結論

配列の長さを求めるには
sizeof(array) / sizeof(array[0])としてやる。

検証用のコード(C99)

#include <stdio.h>

int main()
{
    const int ArrSize = 50;
    int arr[ArrSize];

    printf("sizeof(int) : %d\n", sizeof(int));
    printf("sizeof(arr[0]) : %d\n", sizeof(arr[0]));
    printf("sizeof(arr) : %d\n", sizeof(arr));
    printf("sizeof(arr) / sizeof(int) : %d\n",
        sizeof(arr) / sizeof(int));
    printf("sizeof(arr) / sizeof(arr[0]) : %d\n",
        sizeof(arr) / sizeof(arr[0]));
}

※C99以前ではconst定数を配列のサイズに指定することができないので、
その場合は#defineするしかありません。

実行結果

sizeof(int) : 4
sizeof(arr[0]) : 4
sizeof(arr) : 200
sizeof(arr) / sizeof(int) : 50
sizeof(arr) / sizeof(arr[0]) : 50

検証用のコード(C++)

#include <iostream>

int main()
{
    using namespace std;
    const int ArrSize = 50;
    int arr[ArrSize];

    cout << "sizeof(int) : "
         << sizeof(int) << endl;
    cout << "sizeof(arr[0]) : "
         << sizeof(arr[0]) << endl;
    cout << "sizeof(arr) : "
         << sizeof(arr) << endl;
    cout << "sizeof(arr) / sizeof(int) : "
         << sizeof(arr) / sizeof(int) << endl;
    cout << "sizeof(arr) / sizeof(arr[0]) : "
         << sizeof(arr) / sizeof(arr[0]) << endl;
}

実行結果

sizeof(int) : 4
sizeof(arr[0]) : 4
sizeof(arr) : 200
sizeof(arr) / sizeof(int) : 50
sizeof(arr) / sizeof(arr[0]) : 50

マクロを使ったおまけ(C++)

#include <iostream>

#define ARRAY_LEN(ARR) (sizeof(ARR) / sizeof((ARR)[0]))

int main()
{
    using namespace std;
    const int ArrSize = 50;
    int arr[ArrSize];
    
    cout << "ARRAY_LEN : " << ARRAY_LEN(arr) << endl;
    for (int i = 0; i < ARRAY_LEN(arr); i++) 
    {
        // do anything ...
    }
}

※上記のマクロは多少落とし穴がありますが、
そこはそんなあほなことするなよでよろしくお願いします。
頑張っているところがありました。

※なお、たまに見かける、やっちまったなーなコードは関数で配列をポインタとして
受け取ったもの*1
sizeofして配列の長さを出すつもりが、
実際にはポインタのサイズ(長さ)しか出していないというものです。
そういう場合は長さを渡すか、その配列の長さ用に定義した定数を使うしかないです。

配列のサイズを求める関数とかって標準であるのかなぁ……

*1:この場合 int *arr と受取ろうが、 int arr[] と受取ろうが関数の引数の場合、どっちも単なるポインタとなってしまう