C语⾔数组初始化的三种常⽤⽅法({0},memset,for循环赋值)
以及原理
C语⾔中,数组初始化的⽅式主要有三种:
1、声明时,使⽤ {0} 初始化;
2、使⽤memset;
3、⽤for循环赋值。
那么,这三种⽅法的原理以及效率如何呢? 请看下⾯的测试代码:
[cpp]
1. #define ARRAY_SIZE_MAX  (1*1024*1024)
2.
3. void function1()
4. {
5.    char array[ARRAY_SIZE_MAX] = {0};  //声明时使⽤{0}初始化为全0
6. }
7.
8. void function2()
9. {
10.    char array[ARRAY_SIZE_MAX];
11.    memset(array, 0, ARRAY_SIZE_MAX);  //使⽤memset⽅法
12. }
13.
14. void function3()
15. {
16.    int i = 0;
17.    char array[ARRAY_SIZE_MAX];
18.    for (i = 0; i < ARRAY_SIZE_MAX; i++)  //for循环赋值
19.    {
20.        array[i] = 0;
21.    }
22. }
效率:
分别执⾏上⾯三种⽅法,统计下平均时间可以得出:  for循环浪费的时间最多,{0} 与memset 耗时差不多。
原理:
1、for循环,就是循环赋值,不解释了
2、memset,很容易到memset内部实现代码,这⾥也不解释了
3、{0} 内部是怎么实现的呢?
将上述代码编译成汇编格式如下:
function1如下:
[cpp]
1. pushl  %ebp
2. movl    %esp, %ebp
3. subl    $1048600, %esp
4. leal    -1048584(%ebp), %eax
5. movl    $1048576, %edx
6. movl    %edx, 8(%esp)
7. movl    $0, 4(%esp)
8. movl    %eax, (%esp)
9. call    memset
10. leave
11. ret
function2如下:
[cpp]
1. pushl  %ebp
2. movl    %esp, %ebp
3. subl    $1048600, %esp
4. movl    $1048576, 8(%esp)
5. movl    $0, 4(%esp)
6. leal    -1048584(%ebp), %eax
7. movl    %eax, (%esp)
8. call    memset
9. leave
10. ret
通过汇编代码可以看出,{0}初始化⽅式,调⽤了memset函数!
对三种⽅法的选取:
1、for 最浪费时间,不建议(其实memset内部也是⽤循环实现的,只不过memset经过了严格优化,所以性能更⾼);
2、{0} 可能有移植性问题,虽然绝⼤多数编译器看到{0} 都是将数组全部初始化为0, 但是不保证所有编译器都是这样实现的;
3、综合1、2, 推荐使⽤memset⽅法。
附录:对于{0}初始化的测试
这是很基础的东西,但基础的重要性不⾔⽽喻,我敢肯定这个知识点我肯定曾经了解过,但现在,我不敢确定,由此可见纪录的重要性,这世界没有什么捷径,对⽅向,然后不停重复.所以从今天开始,我会⽐较详细的纪录这些⽐较⼩的知识点,其实还是有不少有意思的地⽅的.
写这篇⽂章的起因在于<<COM技术内幕>>第七章新东西太多,看的我⽬不暇接,所以在⽹上了些例⼦看,其中就有⼀个例⼦中出现了这样的语句:
...
wchar_t wname[128]={0};
char cname[256]={0};
...
我感兴趣的是:
1.这种赋值的结果.
2.这种形式是否符合标准编码规则?
我到了如下资料,可能有助于对这个知识点的掌握.
/*
初始化值的个数可少于数组元素个数.当初始化值的个数少于数组元素个数时,前⾯的按序初始化相应值, 后⾯的初始化为0(全局或静态数组)或为不确定值(局部数组).
*/
我相信上⾯的资料是C和C++语⾔的标准规范,但实际编译器处理时,可能会和规范有所不同.因为编译器原则上要遵从语⾔规范,但对于局部数组的不确定值到底是多少,怎么处理,编译器就可以灵活
处理.我测试了三种编译器,其实编译器赋予的值是固定的,都是0.
⼀直以为 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};
注意没有如下形式的数组赋值:
令数组全部的值为0
void f()
{
v4={'c','d',0};  //错误:不是数组赋值
}
如果你想这样的复制的话,请使⽤ vector(16章第三节) 或者 valarray(22章第四节)。
字符数组可以⽅便地采⽤字符串直接初始化(参考第五章 2.2⼩节)
译注: 就是 这样啦  char  alpha []="abcdefghijklmn";
*/
下⾯来看⼀个例⼦:
#include <iostream.h>
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 <<" " <<array1[n];
cout <<" global static: ";
for(n=0; n<5; n++)
cout <<" " <<array2[n];
cout <<" local: ";
for(n=0; n<5; n++)
cout <<" " <<arr1[n];
cout <<" local static: ";
for(n=0; n<5; n++)
cout <<" " <<arr2[n];
cout <<endl;
}
在这个例⼦中,全局和静态数组都按语⾔规范要求被初始化为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:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。