C語言中,數組初始化的方式主要有三種:
1、聲明時,使用 {0} 初始化;
2、使用memset;
3、用for循環賦值。
那么,這三種方法的原理以及效率如何呢?
請看下面的測試代碼:
#define ARRAY_SIZE_MAX (1*1024*1024)
void function1()
{
char array[ARRAY_SIZE_MAX] = {0}; //聲明時使用{0}初始化為全0
}
void function2()
{
char array[ARRAY_SIZE_MAX];
memset(array, 0, ARRAY_SIZE_MAX); //使用memset方法
}
void function3()
{
int i = 0;
char array[ARRAY_SIZE_MAX];
for (i = 0; i < ARRAY_SIZE_MAX; i++) //for循環賦值
{
array[i] = 0;
}
}
效率:
分別執行上面三種方法,統計下平均時間可以得出:for循環浪費的時間最多,{0} 與memset 耗時差不多。
原理:
1、for循環,就是循環賦值,不解釋了
2、memset,很容易找到memset內部實現代碼,這里也不解釋了
3、{0} 內部是怎么實現的呢?
將上述代碼編譯成匯編格式如下:
function1如下:
pushl %ebp
movl %esp, %ebp
subl $1048600, %esp
leal -1048584(%ebp), %eax
movl $1048576, %edx
movl %edx, 8(%esp)
movl $0, 4(%esp)
movl %eax, (%esp)
call memset
leave
ret
function2如下:
pushl %ebp
movl %esp, %ebp
subl $1048600, %esp
movl $1048576, 8(%esp)
movl $0, 4(%esp)
leal -1048584(%ebp), %eax
movl %eax, (%esp)
call memset
leave
ret
通過匯編代碼可以看出,{0}初始化方式,調用了memset函數!
對三種方法的選取:
1、for 最浪費時間,不建議(其實memset內部也是用循環實現的,只不過memset經過了嚴格優化,所以性能更高);
2、{0} 可能有移植性問題,雖然絕大多數編譯器看到{0} 都是將數組全部初始化為0, 但是不保證所有編譯器都是這樣實現的;
3、綜合1、2, 推薦使用memset方法。
附錄:對於{0}初始化的測試
這是很基礎的東西,但基礎的重要性不言而喻,我敢肯定這個知識點我肯定曾經了解過,但現在,我不敢確定,由此可見紀錄的重要性,這世界沒有什么捷徑,找對方向,然后不停重復.所以從今天開始,我會比較詳細的紀錄這些比較小的知識點,其實還是有不少有意思的地方的.
寫這篇文章的起因在於<>第七章新東西太多,看的我目不暇接,所以在網上找了些例子看,其中就有一個例子中出現了這樣的語句:
...
wchar_t wname[128]={0};
char cname[256]={0};
...
我感興趣的是:
1.這種賦值的結果.
2.這種形式是否符合標准編碼規則?
我找到了如下資料,可能有助於對這個知識點的掌握.
/*
初始化值的個數可少於數組元素個數.當初始化值的個數少於數組元素個數時,前面的按序初始化相應值, 后面的初始化為0(全局或靜態數組)或為不確定值(局部數組).
*/
我相信上面的資料是C和C++語言的標准規范,但實際編譯器處理時,可能會和規范有所不同.因為編譯器原則上要遵從語言規范,但對於局部數組的不確定值到底是多少,怎么處理,編譯器就可以靈活處理.我測試了三種編譯器,其實編譯器賦予的值是固定的,都是0.
在這篇blog中http://hi.baidu.com/widebright/blog/item/a024bc09631402256b60fbd0.html談論了相同的話題,現對其摘錄如下:
/*
一直以為 int a[256]={0};是把a的所有元素初始化為0,int a[256]={1};是把a所有的元素初始化為1.
調試的時查看內存發現不是那么一回事,翻了一下《The C++ Programming Language》總算有定論。PDF的竟然不然復制,就把它這章翻譯了,如下
5.2.1 數組初始化
數組可以用一個列值來初始化,例如
int v1[] ={1,2,3,4};
char v2[]={'a','b','c',0};
當數組定義時沒有指定大小,當初始化采用列表初始化了,那么數組的大小由初始化時列表元素個數決定。所以v1和v2分別為 int[4] 和char[4]類型。如果明確指定了數組大小,當在初始化時指定的元素個數超過這個大小就會產生錯誤。例如:
char v3[2] ={'a','b',0}; //錯誤:太多的初始化值了
char v3[3] ={'a','b',0}; //正確
如果初始化時指定的的元素個數比數組大小少,剩下的元素都回被初始化為 0。例如
int v5[8]={1,2,3,4};
等價於
int v5[8]={1,2,3,4,0,0,0,0};
注意沒有如下形式的數組賦值:
void f()
{
v4={'c','d',0}; //錯誤:不是數組賦值
}
如果你想這樣的復制的話,請使用 vector(16章第三節) 或者 valarray(22章第四節)。
字符數組可以方便地采用字符串直接初始化(參考第五章 2.2小節)
譯注: 就是 這樣啦 char alpha []="abcdefghijklmn";
*/
下面來看一個例子:
#include
int array1[5]={1,2,3};
static int array2[5]={1};
void main()
{
int arr1[5]={2};
static int arr2[5]={1,2};
int n;
cout <<"global: ";
for(n=0; n<5; n++)
cout <<" " <
cout <<" global static: ";
for(n=0; n<5; n++)
cout <<" " <
cout <<" local: ";
for(n=0; n<5; n++)
cout <<" " <
cout <<" local static: ";
for(n=0; n<5; n++)
cout <<" " <
cout <
}
在這個例子中,全局和靜態數組都按語言規范要求被初始化為0,但是局部數組並沒有向前面所說的為不確定值,下面是用gcc,VC6.0,tuborC++分別編譯的結果(注意gcc用g++編譯c++文件,gcc不會鏈接庫的):
/*
GCC 可同時用來編譯 C 程序和 C++ 程序。一般來說,C 編譯器通過源文件的后綴名來判斷是 C 程序還是 C++ 程序。在 Linux 中,C 源文件的后綴名為 .c,而 C++ 源文件的后綴名為 .C 或 .cpp。
但是,gcc 命令只能編譯 C++ 源文件,而不能自動和 C++ 程序使用的庫連接。因此,通常使用 g++ 命令來完成 C++ 程序的編譯和連接,該程序會自動調用 gcc 實現編譯。
*/
GCC:
VC6.0:
TurboC++
這說明了對局部數組沒有初始化的元素的值,這幾種編譯器都將其設置為0。但是,如果如果不對數組進行初始化,即在定義的同時沒有用列表初始化,那么局部數組的值就取決於編譯器而對程序員來說就是不可預料的了。有時間可以測試一下各個編譯器,不過在vc中是0xcc.所以對局部數組的初始化要特別小心。但是全局的數組和靜態數組還是會被正確的賦於0值的。
文章來源:https://www.cnblogs.com/fnlingnzb-learner/p/8057257.html
如果你想更好的提升你的編程能力,學好C語言C++編程!彎道超車,快人一步!
【C語言C++學習企鵝圈子】,分享(源碼、項目實戰視頻、項目筆記,基礎入門教程)
歡迎轉行和學習編程的伙伴,利用更多的資料學習成長比自己琢磨更快哦!
編程學習書籍:
編程學習視頻:
