C++中的数组和局部静态对象

本文探讨了C++中的数组和局部静态对象的特性,包括数组的内存分配、初始化和生命周期。特别提到了局部静态对象的初始化和析构顺序,并通过示例解释了它们在函数调用中的行为。文章还讨论了在不同优化设置下,编译器如何处理字符串常量的合并以及构造函数的调用方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   像以前我说过的,我已经不下五次“以为”我理解数组了,然而今天又一次发现自己无知。

    初学C的时候我把数组当成指针看。明白了一些实现机制后,我开始把数组当成一个特殊的变量; 我开始察看汇编剖析原理,理解逐步深入。 可是,明白得越多,就会发现越多的特例。 最终 —— 我陷入了看似任意且繁杂的规则的迷宫。

 

    还是的回到定义上来。C/C++的数组保证两件事:

    1 数组是由同类型成员组成的构造对象,占有一块连续的内存。

    2 它的名称表示它的首地址。

    仅此而已,除此之外 —— 任何内容都不属于数组的定义。

 

    所以,我们知道,当我们需要数组的时候,我们定义就是了。需要静态数组? C在静态区给你一个数组。 需要自动数组? C在栈上给你一个数组。它还会自动给你初始化:

 

    char str [] = "It's convenient to use arrays";

 

    于是栈上有了我们需要的、不折不扣刚好30字节的空间,当我们用str索引他的时候,他已经有需要的内容了。 这就是C/C++。他选取了最精确的定义,而隐藏繁杂的后台。一切都有可能改变,唯有概念不变。

 


   ANSI C++98太厚了, 一时还没法学会在里面找到自己要东西。下面是我的一些总结:

 

    1 首先谈谈函数内定义的普通数组,即auto数组。 auto 数组的的确确实在栈上建立的,且(可以认为)在定义的位置初始化。 所以,若你希望用一个数组实现一个颇大的正弦速查表,推荐还是改用指针 —— 系统切切实实会在栈上初始化一个结结实实的巨大 auto 数组。

     auto数组在离开作用域后,其内存就被回收了 —— 按照C的说法,你不应该继续用它了。这的确就是我们编写程序需要用到的所有知识 —— 不过,若想刨根问底,稍候,我也会谈到这是一个怎么样的内部过程。

 

    2 static 数组是怎么回事呢?

    C和C++中有很多 static 。 可以说,每种 static 都不是一回事。

     static 数组都存储在静态数据域中。这里要细谈的是局部 static 数组的初始化:
    局部static对象当你第一次用的时候初始化;主程序结束时,所有初始化过的局部static 对象按和构造相反的顺序析构  —— 然后全局对象才开始析构。

 


   面是一个我曾研究过很长时间的一个经典问题,在此剖析一下:

 

    char* getHello(){
      char str[] = "hello world";

### C++ 静态数组初始化方法 在 C++ 中,静态数组的初始化可以通过多种方式进行。以下是一些常见的初始化方法: #### 1. 使用大括号进行初始化 C++ 支持通过大括号 `{}` 来初始化数组。如果提供的初始值少于数组的大小,剩余的元素会被自动初始化为 `0`[^1]。 ```cpp int arr[5] = {1, 2, 3}; // 初始化前三个元素,其余两个元素自动设置为0 ``` #### 2. 不指定数组大小 当使用大括号初始化时,可以省略数组的大小声明,编译器会根据初始值的数量自动推断数组的大小[^3]。 ```cpp int arr[] = {1, 2, 3, 4, 5}; // 数组大小由初始值数量决定 ``` #### 3. 单一值初始化 如果只提供一个初始值,所有元素都会被初始化为该值。这种情况下,数组的所有元素会被设置为相同的值[^1]。 ```cpp int arr[5] = {0}; // 所有五个元素都被初始化为0 ``` #### 4. 默认初始化 如果不提供任何初始值,局部数组的元素将不会被初始化(包含未定义值),而全局或静态数组的元素会被默认初始化为 `0`[^4]。 ```cpp int arr[5]; // 局部数组,元素未初始化 static int staticArr[5]; // 全局或静态数组,元素被初始化为0 ``` #### 5. C++11 及以后版本中的花括号初始化 从 C++11 开始,可以使用花括号 `{}` 进行更安全的初始化,避免了窄化转换的问题[^1]。 ```cpp int arr[5] = {0, 1, 2, 3, 4}; // 明确指定每个元素的值 double dArr[3] = {1, 2.5, 3}; // 花括号初始化支持不同类型 ``` #### 6. 动态初始化(不推荐用于静态数组) 虽然动态初始化通常用于动态分配数组,但也可以尝试对静态数组进行类似操作。不过,这种方式可能会导致性能问题,并且不如直接初始化直观。 ```cpp int size = 5; int arr[size] = {0}; // 非标准扩展,可能不被所有编译器支持 ``` --- ### 示例代码 以下是一个综合示例,展示了多种初始化方法: ```cpp #include <iostream> using namespace std; int main() { // 方法1:部分初始化 int arr1[5] = {1, 2}; for (int i = 0; i < 5; ++i) cout << arr1[i] << " "; // 输出: 1 2 0 0 0 cout << endl; // 方法2:省略大小 int arr2[] = {3, 4, 5}; for (int i = 0; i < 3; ++i) cout << arr2[i] << " "; // 输出: 3 4 5 cout << endl; // 方法3:单一值初始化 int arr3[4] = {0}; for (int i = 0; i < 4; ++i) cout << arr3[i] << " "; // 输出: 0 0 0 0 return 0; } ``` --- ### 注意事项 - 在 C++ 中,数组的大小必须是一个常量表达式,因此不能使用变量来定义数组大小(除非使用动态内存分配或 C99 的可变长度数组扩展)[^4]。 - 如果需要更灵活的数组管理,可以考虑使用 `std::vector`,它提供了动态调整大小的功能[^2]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值