【C言語】
二次元配列とポインタ配列で効率が良いのはどちら?

2次元配列vs ポインタ配列

■ポインタ配列の使用例

#include    <stdio.h>
#if 0
char *argv[]    
+--------+
|char *  -> "0123456789abcdef"
+--------+
|char *  -> "01234567"
+--------+
|char *  -> "0123", 
+--------+
|char *  ->| "01"
+--------+
....

#endif
static char    *argv[] = {
    "0123456789abcdef"  ,
    "01234567"          ,
    "0123"              ,
    "01"                ,
    "0"                 ,
    ""                  ,
    "0"                 ,
    "01"                ,
    "0123"              ,
    "01234567"          ,
    "0123456789abcdef"  ,
    "99999999"          ,
    NULL
};
int main(void){
    const size_t 行 = sizeof(argv)/sizeof(argv[0]);
    printf("sizeof(argv) = %zu*%zu = %zu\n",sizeof(char *),行,sizeof(argv));
    for(int i = 0; argv[i] != NULL;i++){
        printf("argv[%d]=\"%s\"\n",i,argv[i]);
    }
}

➡ポインタ配列版の実行結果

sizeof(argv) = 8*13 = 104
argv[0]="0123456789abcdef"
argv[1]="01234567"
argv[2]="0123"
argv[3]="01"
argv[4]="0"
argv[5]=""
argv[6]="0"
argv[7]="01"
argv[8]="0123"
argv[9]="01234567"
argv[10]="0123456789abcdef"
argv[11]="99999999"

■二次元配列の使用例

#include    <stdio.h>
#include    <string.h>
#if 0
char dim2[][16]    E='\0'
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f| 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|2|3|4|5|6|7|E| | | | | | | | 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|2|3|E| | | | | | | | | | | | 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|E| | | | | | | | | | | | | | 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|E| | | | | | | | | | | | | | | 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|E| | | | | | | | | | | | | | | | 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
....
#endif
static char dim2[][16] ={
    "0123456789abcdef"  ,   //一番長い行
    "01234567"          ,
    "0123"              ,
    "01"                ,
    "0"                 ,
    ""                  ,
    "0"                 ,
    "01"                ,
    "0123"              ,
    "01234567"          ,
    "0123456789abcdef"  ,   //一番長い行
    "99999999"          ,
};
int main(void){
    const size_t 行 = sizeof(dim2)/sizeof(dim2[0]);
    const size_t 列 = strlen("0123456789abcdef") ;  //一番長い行の長さ=16文字
    printf("sizeof(dim2) = 行:%zu*列:%zu=%zu\n",行,列,sizeof(dim2));
    for(size_t i = 0; i < 行;i++){
        printf("dim2[%zu]=\"%s\"\n",i,dim2[i]);
    }
}

➡二次元配列版実行結果

sizeof(dim2) = 行:12*列:16=192
dim2[0]="0123456789abcdef01234567"
dim2[1]="01234567"
dim2[2]="0123"
dim2[3]="01"
dim2[4]="0"
dim2[5]=""
dim2[6]="0"
dim2[7]="01"
dim2[8]="0123"
dim2[9]="01234567"
dim2[10]="0123456789abcdef99999999"
dim2[11]="99999999"

■ポインタ配列と二次元配列の違いまとめ

このプログラムの場合

(1) 二次元配列は
末尾に番兵のNULLポインタを置けない。
(2) 二次元配列は
行 x 列のメモリサイズを必要とし、
argv[]より効率が悪い(メモリサイズが増える)。
(3) 一番長い行の長さが変わる度に
人間が長さを数えて配列要素数の変更が必要。
(4) 人間が配列要素数に終端文字\0の考慮を忘れても
コンパイラは警告もエラーも出してくれない。
(5) このプログラムではdim2[0],dim2[10]参照時
終端文字\0が無いので暴走する。