読者です 読者をやめる 読者になる 読者になる

配列の引数を sizeof してもポインタのサイズしか返ってこない

c

C の sizeof はデータ型の大きさを求める演算子。変数や型のメモリサイズを返します。
ところで、配列やポインタの sizeof を計算するとどうなるでしょうか?

#include <stdio.h>

int main( int argc, char** argv )
{
    char array[] = "hogehoge";
    char* pointer;

    pointer = array;

    printf( "array : %s\n", array );     // array : hogehoge 
    printf( "pointer : %s\n", pointer ); // pointer : hogehoge

    printf( "sizeof array : %d\n", sizeof array );     // array : 9
    printf( "sizeof pointer : %d\n", sizeof pointer ); // pointer : 4

    return 0;
}

配列に対しては配列全体のサイズ(要素数ではない、ここでは 9 = 1 x 9)を返し、ポインタに対してはポインタ自身のサイズ(ここでは 4)を返します。
ということは、こう書けば dst のサイズに合わせてセキュアに文字列をコピーしてくれる strncpy2() がシンプルに書けるんじゃないかと期待したんですが、撃沈。

#include <stdio.h>

char* strncpy2( char dst[], const char src[] )
{
    strncpy( dst, src, sizeof dst );
    dst[(sizeof dst) - 1] = '\0';

    return dst;
}

int main( int argc, char** argv )
{
    char array[] = "hogehoge";
    char dst[5];

    strncpy2( dst, array );
    printf( "dst : %s\n", dst );     // "dst : hog" ← hoge + '\0' にならない!

    return 0;
}

原因は、strncpy2() 内の sizeof dst が配列サイズの 5 ではなく、ポインタのサイズ 4 を返すため。

char* strncpy2( char dst[], const char src[] )
{
    printf( "sizeof dst : %d\n", sizeof dst ); // sizeof dst : 4 !
    strncpy( dst, src, sizeof dst );
    dst[(sizeof dst) - 1] = '\0';

    return dst;
}

つまり、関数定義の引数の型を配列にして、かつ実行時に実際に引数として配列を渡しても、呼ばれた関数内ではポインタと同じ扱いで処理されているようです。
ということで、配列のサイズを期待して sizeof を使うときは、同じ関数内で宣言しているかどうか確認が必要ということでした。