当前位置: 代码网 > it编程>编程语言>C/C++ > C/C++中使用局部/全局变量初始值或默认值问题

C/C++中使用局部/全局变量初始值或默认值问题

2024年08月21日 C/C++ 我要评论
在c语言中的全局变量和静态变量都是会自动初始化为0,堆和栈中的局部变量不会初始化而拥有不可预测的值。c++保证了所有对象与对象成员都会初始化,但其中基本数据类型的初始化还得依赖于构造函数。下文来详细探

在c语言中的全局变量和静态变量都是会自动初始化为0,堆和栈中的局部变量不会初始化而拥有不可预测的值。

c++保证了所有对象与对象成员都会初始化,但其中基本数据类型的初始化还得依赖于构造函数。

下文来详细探讨c风格的”默认初始化”行为,以及c++中成员变量的初始化规则。

一、初始化的语法

很多人至今不知道c++中如何正确地初始化一个变量,我们首先来解决语法的问题。

c语言中在声明时用=即可完成初始化操作。但我们偏向于使用c++风格(本文中均指面向对象程序设计风格)来初始化内置类型:

// c 风格
int i = 3;
int arr[] = {1, 2, 3}; 
// c++ 风格
int i(3);
int i = int(3);
int *p = new int(3);
int* arr = new int[3] {1, 2, 3};

在c语言中int a;表示声明了整型a但未初始化,而c++中的对象总是会被初始化的,无论是否写了圆括号或者是否写了参数列表,例如:

int basic_var;      // 未初始化:应用"默认初始化"机制
cperson person;     // 初始化:以空的参数列表调用构造函数

二、默认初始化规则

定义基本数据类型变量(单个值、数组)的同时可以指定初始值,如果未指定c++会去执行默认初始化(default-initialization)。 那么什么是”默认初始化”呢?

  • 1.栈中的变量(函数体中的自动变量)和堆中的变量(动态内存)会保有不确定的值;
  • 2.全局变量和静态变量(包括局部静态变量)会初始化为零;
  • 3.(lanyan注)函数体中的自动变量在有些编译器下(我的是clion2021.3),虽然在未初始化的情况下输出也是0,但是编译时会出现警告,所以这样写是不对的。

所以函数体中的变量定义是这样的规则:

//c++中
int i;                    // 不确定值
int i = int();            // 0
int *p = new int;         // 不确定值
int *p = new int();       // 0

三、静态和全局变量的初始化

未初始化的和初始化为零的静态/全局变量编译器是同样对待的,把它们存储在进程的bss段(这是全零的一段内存空间)中。所以它们会被”默认初始化”为零。

来看例子:

int g_var;
int *g_pointer;
static int g_static;
 
int main(){
    int l_var;
    int *l_pointer;
    static int l_static;
 
    cout<<g_var<<endl<<g_pointer<<endl<<g_static<<endl;
    cout<<l_var<<endl<<l_pointer<<endl<<l_static<<endl;
};

输出:

0                   // 全局变量
0x0                 // 全局指针  
0                   // 全局静态变量
32767               // 局部变量
0x7fff510cfa68      // 局部指针
0                   // 局部静态变量

动态内存中的变量在上述代码中没有给出,它们和局部变量(自动变量)具有相同的”默认初始化”行为。

四、成员变量的初始化

成员变量分为成员对象和内置类型成员,其中成员对象总是会被初始化的。而我们要做的就是在构造函数中初始化其中的内置类型成员。

class a{
public:
    int v;
};
a g_var;
 
int main(){
    a l_var;
    static a l_static;
    cout<<g_var.v<<' '<<l_var.v<<' '<<l_static.v<<endl;
    return 0;
}

输出:

0 2407223 0

可见内置类型的成员变量的”默认初始化”行为取决于所在对象的存储类型,而存储类型对应的默认初始化规则是不变的。 所以为了避免不确定的初值,通常会在构造函数中初始化所有内置类型的成员。

effective c++: item 4一文讨论了如何正确地在构造函数中初始化数据成员。

这里就不展开了,直接给出一个正确的初始化写法:

class a{
public:
    int v;
    a(): v(0);
};

五、封闭类嵌套成员的初始化

再来探讨一下当对象聚合发生时成员变量的”默认初始化”行为,同样还是只关注于基本数据类型的成员。

class a{
public:
    int v;
};
 
class b{
public:
    int v;
    a a;
};
 
b g_var;
int main(){
    b l_var;
    cout<<g_var.v<<' '<<g_var.a.v<<endl;
    cout<<l_var.v<<' '<<l_var.a.v<<endl;
    return 0;
}

结果:

0 0
43224321 -1610612736

规则还是是一样的,默认初始化行为取决于它所属对象的存储类型。

封闭类(enclosing)中成员对象的内置类型成员变量的”默认初始化”行为取决于当前封闭类对象的存储类型,而存储类型对应的默认初始化规则仍然是不变的。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com