c++数组初始化与删除用法大全

0.前言

大家公认的c++学习曲线比较陡峭,在我看来很重要一个原因就是c++语法比较灵活,要实现某个功能可能有好多种写法都能实现,所以很多时候就容易给大家带来困扰,搞不清楚为什么要这么写,或者这么写到底为啥,跟我平时写的为什么不一样。比如我们常用的数组,其初始化/删除就有非常多的方式,而且这些方式也比较混乱,没有特别的规律,很容易把人给直接绕晕圈了。下面我们来针对数组的初始化/删除方式做一个总结,如果有不对或者不全的地方,大家可以进行指正补充。

1.静态初始化

比较常见的初始化方式为静态初始化。下面我们来看实例

void static_init() {
    int a[5] = {1, 2, 3, 4, 5};
    int b[3] = {1};
    int c[5] = {1,};
    const int n = 3;
    int d[n] = {1, 2, 3};
    for(int i=0; i<sizeof(a)/sizeof(a[0]); i++) cout<<a[i]<<" ";
    cout<<endl;
    for(int i=0; i<sizeof(b)/sizeof(b[0]); i++) cout<<b[i]<<" ";
    cout<<endl;
    for(int i=0; i<sizeof(c)/sizeof(c[0]); i++) cout<<c[i]<<" ";
    cout<<endl;
    for(int i=0; i<sizeof(d)/sizeof(d[0]); i++) cout<<d[i]<<" ";
    cout<<endl;

}
1 2 3 4 5 
1 0 0 
1 0 0 0 0 
1 2 3 

上面的写法都是可以的。
数组a的初始化方法最为常见,直接用大括号初始化,大括号内的元素个数与数组声明时长度一致。
数组b大括号内的元素小于数组声明长度,不足的元素按0的默认值填充。
数组c的初始化方式与b类似。值得注意的是,在有些资料上会说c的方式有错误,但是经过本人实测,c的初始化方式是可以正常运行的,c++版本为11。
数组d初始化时长度为变量n,注意此时必须要求n为const类型,否则会报错。

以下方式均为错误的。

   // int n = 3;
    // int f[n] = {1, 2, 3}; error: variable-sized object may not be initialized
    // int f[5] = {1,,1};  error: int [5]{(int)1, (), ()}
    // int f[5] = {1, 2, 3, 4, 5, 6}; error: excess elements in array initializer

2.字符串常量初始化字符数组

我们还经常用字符串常量初始化字符数组,这种用法特别常见。

void char_init() {
    char cs[8] = "abcedfg";
    char c2[5] = "abc";
    cout<<sizeof(cs)<<endl;
    cout<<sizeof(c2)<<endl;
}

上面都是用一个字符串初始化字符数组,注意默认会在字符数组最后加上’\0’。如果字符常量长度不够数组其他元素自动初始化为 ‘\0’。

3.不指定长度初始化

void other_init() {
    int nums[] = {1, 2, 3};
    cout<<sizeof(nums)/sizeof(nums[0])<<endl;
}

上面的代码最终会输出3。初始化的时候,没有专门指定数组长度,但是列表内的元素个数会决定数组长度。

4.动态初始化数组

void dynamic_init() {
    int *a = new int[3];
    for(int i=0; i<3; i++) cout<<a[i]<<" ";
    cout<<endl;
    int *b = new int[3]();
    for(int i=0; i<3; i++) cout<<b[i]<<" ";
    cout<<endl;
    memset(b, 1, sizeof(int)*3);
    for(int i=0; i<3; i++) cout<<b[i]<<" ";
}

上面代码输出:

0 0 0 
0 0 0
16843009 16843009 16843009

动态初始化数组,则利用到了new关键字。使用new时,如果在运行阶段需要数组,则创建它;如果不需要,则不创建。还可以在程序运行时选择数组的长度。这被称为动态联编。意味着数组是在程序运行时创建的。这种数组叫做动态数组。在运行时确定数组的长度。

new出来的数据,需要用一个指针接收,返回的则是第一个元素的地址。
另外注意的是,new int[3]与new int3的效果一致,最后得到的都是默认值为0长度为3的一个整型数组。

另外我们需要注意的是,用memset函数时,进行设置时候,是一个字节一个字节进行设置。上面的写法,是将数组b的每个字节都设置为1,即0x01010101,换算成对应的十进制则为16843009。

5.删除动态数组

void dynamic_v2() {
    int *p = new int[3];
    p[0]=0, p[1]=1, p[2]=2;
    for(int i=0; i<3; i++) cout<<p[i]<<" ";
    cout<<endl;

    *p=10, *(p+1)=11, *(p+2)=12;
    for(int i=0; i<3; i++) cout<<p[i]<<" ";
    cout<<endl;

    *p=20, *(++p)=21, *(++p)=22;
    p-=2; // 注意此时p已经指向了第三个元素,需要先减2回到起始位置
    for(int i=0; i<3; i++) cout<<p[i]<<" ";
    cout<<endl;

    delete [] p;
    for(int i=0; i<3; i++) cout<<p[i]<<" ";
}
0 1 2 
10 11 12 
20 21 22 
20 21 22 

使用new与delete时,我们需要注意以下事项:
1.delete不能释放不是new关键字分配的内存。
2.delete不能释放同一个内存两次。
3.如果是用new []为数组分配内存,则我们应该使用delete []释放。
4.对空指针进行delete是可以的,安全的。

上面代码需要注意的是:我们对p进行delete操作以后,似乎还能访问到原内存中的数据,这个就比较奇怪了,为什么会这样?

指针被delete以后,并没有被设置为NULL,此时delete只是把指针所指向的内存给释放掉,并没有把指针本身干掉,此时指针指向的是“垃圾”内存,这种指针成为悬挂指针(dangling pointer)。

所以一般我们delete完以后,可以将指针设置为NULL。

你可能感兴趣的:(c/c++,数组初始化,静态初始化,动态初始化,删除)