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

原文: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的操作,失之毫厘谬以千里!
如果实在想再初始化,那么老老实实循环赋值吧。

【转】c++数组初始化的更多相关文章

  1. Linux Kernel代码艺术——数组初始化

    前几天看内核中系统调用代码,在系统调用向量表初始化中,有下面这段代码写的让我有点摸不着头脑: const sys_call_ptr_t sys_call_table[__NR_syscall_max+ ...

  2. 用vector容器代替数组 ——使用数组初始化vector对象

    在C++中,我们不能用数组直接初始化另一数组,而只能创建新的数组,然后显式的把原数组的元素逐个复制给新的数组. 按照C语言中的做法: const size_t arry_size=6; int int ...

  3. java数组初始化

    java数组初始化 //静态初始化数组:方法一 String cats[] = new String[] { "Tom","Sam","Mimi&qu ...

  4. java 数组初始化

    一维数组 1)   int[] a;   //声明,没有初始化 2)   int[] a=new int[5];   //初始化为默认值,int型为0 3)   int[] a={1,2,3,4,5} ...

  5. [转]Java数组初始化详解

    一维数组1)   int[] a;   //声明,没有初始化 2)   int[] a=new int[5];   //初始化为默认值,int型为0 3)   int[] a={1,2,3,4,5}; ...

  6. C++中数组初始化

    #include<iostream>using std::cout;using std::endl;int arr1[5];int arr2[5] = {1,3,5};int main() ...

  7. 通过数组初始化链表的两种方法:指向指针的引用node *&tail和指向指针的指针(二维指针)node **tail

    面试高频题:单链表的逆置操作/链表逆序相关文章 点击打开 void init_node(node *tail,char *init_array) 这样声明函数是不正确的,函数的原意是通过数组初始化链表 ...

  8. No1_3.数组初始化_Java学习笔记

    public class HelloArray { public static void main(String[] args) { // TODO Auto-generated method stu ...

  9. 数组初始化(c, c++, gcc, g++)

    这是很基础的东西,但基础的重要性不言而喻,我敢肯定这个知识点我肯定曾经了解过,但现在,我不敢确定,由此可见纪录的重要性,这世界没有什么捷径,找对方向,然后不停重复.所以从今天开始,我会比较详细的纪录这 ...

  10. c语言数组初始化问题

    2147483648字符数组的初始化,最容易理解的方式就是逐个字符赋给数组中各元素. charstr[10]={'I','','a','m','',‘h’,'a','p','p','y'}; 即把10 ...

随机推荐

  1. 吃CPU的openmp 程序

    g++ -o eat -fopenmp eat.cpp #include "stdio.h" int main(int argc, char *argv[]) { #pragma ...

  2. spark安装和登陆配置

    1.下载安装包: http://www.igniterealtime.org/downloads/index.jsp 2.点击安装后打开登陆界面: 2.点击“高级”,设置相关配置: 3.点击“登陆”后 ...

  3. 动态点分治入门 ZJOI2007 捉迷藏

    传送门 这道题好神奇啊……如果要是不带修改的话那就是普通的点分治了,每次维护子树中距离次大值和最大值去更新. 不过这题要修改,而且还改500000次,总不能每改一次都点分治一次吧. 所以我们来认识一个 ...

  4. [OS][FS]查看ext3文件系统分区的superblock

    本文将介绍怎样读取一个分区的superblock: 1. 首先我们查看一下在磁盘上有哪些分区,通过fdisk -l 这里有三个分区,我们下面查看/dev/sda3(这是一个device file) 2 ...

  5. light oj 1032(数位DP)

    求一段区间中,每个十进制数所对应的二进制数中连续的1的个数之和. 设dp[i][0]代表长度为i的二进制数,首位为0,所含有的连续的1的个数之和. dp[i][1]代表长度为i的二进制数,首位为1,所 ...

  6. 小程序-demo:天气预报

    ylbtech-小程序-demo:天气预报 1.返回顶部 1.app.js //app.js App({ //系统事件 onLaunch: function () {//小程序初始化事件 var th ...

  7. js读取ognl表达式的内容

    <input type="hidden" id="number"   value='<s:property  value="resultN ...

  8. java笔记之线程方式1启动线程

    * 需求:我们要实现多线程的程序. * 如何实现呢? *   由于线程是依赖进程而存在的,所以我们应该先创建一个进程出来. *   而进程是由系统创建的,所以我们应该去调用系统功能创建一个进程. * ...

  9. Linux 常用命令七 grep

    一.grep命令 grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜 ...

  10. bzoj 4521: [Cqoi2016]手机号码【数位dp】

    比较基础的数位dp,dfs的时候带上上一位,上上位,是否已经有连续3个相同位,是否有4,是否有8即可 但是要注意两点(在洛谷上一直70) 当l=1e10的时候,直接输出clc(r)即可,因为如果再减去 ...