数组初始化列表中的元素个数小于指定的数组长度时,不足的元素补以默认值。

原文:C/C++数组初始化的一些误区

以前我这样初始化一个数组,并自我感觉良好:

int a[] = {  };    // 全部初始化为0

这种简单的写法让我非常爽,于是我又想把数组全部初始化为1:

int a[] = {  };    // 我想全部初始化为1

直到十分钟前,我都以为这句代码确实能够将5个元素全部初始化为1,但事实跟我想的完全不同!(基础的东西革命的本钱,疏漏不得啊)

全部初始化为0的那行代码确实是没问题的,可以正常工作。问题就出在想把数组全部初始化成一个非0的数,即非默认值,是行不通的(查看内存发现,只有数组的第一个元素被初始化为1,其他全为0)。这倒不是因为编译器对初始化为0给了个后门,而是因为一条基本语法规则:

数组初始化列表中的元素个数小于指定的数组长度时,不足的元素补以默认值。

对于基本类型int来说,当然就是补int()即0了。再看一下非基本类型的数组:

string a[] = { "foo" };
有了上面的规则,就很容易知道其实相当于:
string a[] = { "foo", "", "", "", "" };

即后面4个元素调用了string的默认构造函数进行的初始化,而第一个则调用的string::string(const char*)进行的初始化。

还有一个区别:

int a[];
string a[];

如果不明确指出初始化列表,那么基本类型是不会被初始化的(除全局变量和静态变量外),所有的内存都是“脏的”;而类类型则会为每个元素调用默认构造函数进行初始化。

注意,在C++11中中间的赋值号可以省略,即 int a[5]{1}; 并且,如果初始化列表为空,如 int a[5]{};,那将初始化所有元素为默认值,即与 int a[5]{0}; 等价

 

动态数组的初始化

说完了栈中的数组的初始化,我发现new一个数组和其又有一些不同:
int* a = new int[];

string* a = new string[];

int* a = new int[] {  };

string* a = new string[] { "foo" };
上面几行代码遵循栈中数组的初始化规则,除此之外这里还有一个新语法:

int* a = new int[]();
 

注意后面的一对圆括号,它的意思是使用默认值初始化整个数组,所以对于类类型来说,new string[5] 与 new string[5]()是等价的,都会调用默认构造函数进行初始化;但是对于基本类型就不同了,new int[5]根本不会初始化,而new int[5]() 则会使用int()的值即0进行初始化。

看到这对圆括号,我想它该不会是元素的构造函数的参数列表吧,那么我可能会想将数组全部初始化为1:new int[5](1); 看起来很合理,但其实不行。事实上这对圆括号不是数组元素的构造参数,可能是整个数组的,它有三个重载版本:
 
 
看起来像是常引用、右值引用、和默认版本。所以假如已经有一个相同大小的数组b,试着用b来初始化a:

int* a = new int[](b);
 

结果编译出错,提示error C3074: an array cannot be initialized with a parenthesized initializer,看来这个括号的作用和我想的不一样,其实也应该看出来的,要是是用另一个数组初始化的话那么参数应该是const int (&)[5] 而不是 const int [5] &,而且后者好像是一个错误的类型。这个问题暂时无解。

错过了初始化时机(memset的误区)

如果想在数组创建结束后再对其进行初始化,可以使用C函数memset(),但是memset的使用有个大问题,就是它只对char类型的数组管用:
char a[];

memset(a, , ); // 将每个元素设置为1
如果将上面的a数组换成int或其他类型的,就会出现问题,因为memset的内部实现是以字节为单位进行赋值的,int 类型大于一个字节(假设是4个),数组内存连续,如果有下面代码:
int a[];
memset(a, , sizeof(a));
将只会对前sizeof(a)即40个字节进行赋值1的操作,即给“前5个int”进行了赋值0x01010101的操作,失之毫厘谬以千里!
如果实在想再初始化,那么老老实实循环赋值吧。

最新文章

  1. 安卓DJ113舞曲网应用客户端 项目源码(服务器+客户端)
  2. HTTP协议—— 简单认识TCP/IP协议
  3. Ninject之旅之八:Ninject插件模型(附程序下载)
  4. Demonstrating One-Shot Execution TimerTask Timer
  5. Java中static和final的区别
  6. vs查看虚函数表和类内存布局
  7. firefox如何restart重启
  8. javascript--自己用的插件
  9. express设置ejs并将后缀改为html
  10. .NET通过PowerShell操作ExChange为用户开通邮箱账号
  11. Javascript 生成指定范围数值随机数
  12. node.js 学习随笔
  13. Mybatis基础学习(五)—缓存
  14. 在windows和Linux上安装ImageMagick与jmagick,Maven配置、Java图片压缩代码(整理网上、结合自己情况、编写出来的新安装方式)
  15. 结构化您的Python工程
  16. Pytorch 常用函数
  17. 「FJOI2016」神秘数 解题报告
  18. [UE4]Canvas Panel
  19. TZOJ 2546 Electricity(去掉割点后形成的最大连通图数)
  20. 1 、在Linux(centos6.8)系统下的JDK安装与配置

热门文章

  1. 【idea】idea快捷键
  2. 【Selenium】软件测试基础(软件测试分类和工具组)firebug、firepath的安装
  3. 并不对劲的p2664树上游戏
  4. LR:HTML-based script和URL-based script方式录制的区别
  5. linuxmint17.3提示flash不是最新版本解决方法(copy)
  6. bzoj 1997: [Hnoi2010]Planar【瞎搞+黑白染色】
  7. P3755 [CQOI2017]老C的任务
  8. 关于浮动与清浮动 float
  9. 《windows核心编程系列》十七谈谈dll
  10. Hdu 5407 CRB and Candies (找规律)