■この記事の概要
この記事では、C言語における配列とポインタの違いを解説し、どちらがより効率的かを処理速度の観点から比較しています。
strcpy
関数を用いた実例をもとに、配列・ポインタの各使用方法による実行時間の差を測定し、具体的なデータを示しています。
■配列vsポインタ
文字列定数を変数に設定する際、
以下のように配列とポインタで似たような記述が出来ます。
char ary[1024] = “string”;
char *ptr = “string”;
しかし似たような記述でも
プログラムの実行時間が大きく異なります。
関数ポインタを使って処理時間を比較してみましょう。
■配列[要素数有り]版
void func1(char *p){
char funcname[1024] = "関数の名前等の固定文字列";
strcpy(p,funcname);
}
左辺の funcname[1024]へ
右辺の文字列をコピーする命令が実行されます。
さらに余った所を1024byteになるまで0でクリアするので
処理時間が一番かかります。
■配列[要素数無し]版
void func2(char *p){
char funcname[] = "関数の名前等の固定文字列";
strcpy(p,funcname);
}
左辺の funcname[]へ
右辺の文字列をコピーする命令が実行されます。
右辺の文字列が長い程コピーに時間がかかります。
■ポインタ版
void func3(char *p){
char *funcname = "関数の名前等の固定文字列";
strcpy(p,funcname);
}
左辺のポインタへ
右辺の文字列のアドレスを代入しているだけななので
文字列のコピーは発生しません。
右辺の文字列が長くても短くても処理時間は同じです。
■__func__ 相当版
void func4(char *p){
static const char funcname[] = "関数の名前等の固定文字列";
strcpy(p,funcname);
}
static が付いているので
メモリ中の文字列リテラルにfuncnameという
名前が付いた状態です。
コピー処理は実行されません。
■関数ポインタを使った処理時間計測コード
//【C言語】関数ポインタを使った配列vsポインタの処理時間計測
#include <stdio.h>
#include <string.h>
#include <time.h>
//配列[要素数有り]
void func1(char *p){
char funcname[1024] = "関数の名前等の固定文字列";
strcpy(p,funcname);
}
//配列[要素数無し]
void func2(char *p){
char funcname[] = "関数の名前等の固定文字列";
strcpy(p,funcname);
}
//ポインタ
void func3(char *p){
char *funcname = "関数の名前等の固定文字列";
strcpy(p,funcname);
}
// __func__ 事前定義マクロ相当
void func4(char *p){
static const char funcname[] = "関数の名前等の固定文字列";
strcpy(p,funcname);
}
typedef void (*関数ポインタ_型)(char *);
static inline void 時間計測(
int id,
関数ポインタ_型 計測対象関数,
char *buf
){
clock_t start = clock();
const int max = 0x7fffFFF ;
for(int i = 0;i<max ;i++){
計測対象関数(buf+(i%500));
}
clock_t end = clock();
printf("id=%d %8ld clock\n",id, end - start);
}
char gbuf[1024];
int main(void){
char abuf[1024];
puts("自動変数へ出力");
時間計測(1,func1,abuf);
時間計測(2,func2,abuf);
時間計測(3,func3,abuf);
時間計測(4,func4,abuf);
puts("外部変数へ出力");
時間計測(4,func4,gbuf);
時間計測(3,func3,gbuf);
時間計測(2,func2,gbuf);
時間計測(1,func1,gbuf);
}
func1()~func4()のどれが一番遅いか予想してください。
ご自分の環境でコピペしてコンパイル実行してみましょう。
●実行結果
+ gcc -O vs.c
+ ./a.out
自動変数へ出力
id=1 5250000 clock
id=2 1546875 clock
id=3 375000 clock
id=4 328125 clock
外部変数へ出力
id=4 359375 clock
id=3 375000 clock
id=2 1562500 clock
id=1 5234375 clock
+ clang -O vs.c
+ ./a.out
自動変数へ出力
id=1 3562500 clock
id=2 1468750 clock
id=3 296875 clock
id=4 328125 clock
外部変数へ出力
id=4 312500 clock
id=3 296875 clock
id=2 1484375 clock
id=1 3625000 clock
id=3の【ポインタ版】に対して
id=1の【配列[要素数有り]版】版が
10倍以上遅いのが
筆者の環境で計測されました。
ご自身の環境でも実験してみて下さい。
参考: