C/C++中使用局部/全局變量初始值或默認(rèn)值問題
在C語(yǔ)言中的全局變量和靜態(tài)變量都是會(huì)自動(dòng)初始化為0,堆和棧中的局部變量不會(huì)初始化而擁有不可預(yù)測(cè)的值。
C++保證了所有對(duì)象與對(duì)象成員都會(huì)初始化,但其中基本數(shù)據(jù)類型的初始化還得依賴于構(gòu)造函數(shù)。
下文來詳細(xì)探討C風(fēng)格的”默認(rèn)初始化”行為,以及C++中成員變量的初始化規(guī)則。
一、初始化的語(yǔ)法
很多人至今不知道C++中如何正確地初始化一個(gè)變量,我們首先來解決語(yǔ)法的問題。
C語(yǔ)言中在聲明時(shí)用=即可完成初始化操作。但我們偏向于使用C++風(fēng)格(本文中均指面向?qū)ο蟪绦蛟O(shè)計(jì)風(fēng)格)來初始化內(nèi)置類型:
// C 風(fēng)格
int i = 3;
int arr[] = {1, 2, 3};
// C++ 風(fēng)格
int i(3);
int i = int(3);
int *p = new int(3);
int* arr = new int[3] {1, 2, 3};在C語(yǔ)言中int a;表示聲明了整型a但未初始化,而C++中的對(duì)象總是會(huì)被初始化的,無論是否寫了圓括號(hào)或者是否寫了參數(shù)列表,例如:
int basic_var; // 未初始化:應(yīng)用"默認(rèn)初始化"機(jī)制 CPerson person; // 初始化:以空的參數(shù)列表調(diào)用構(gòu)造函數(shù)
二、默認(rèn)初始化規(guī)則
定義基本數(shù)據(jù)類型變量(單個(gè)值、數(shù)組)的同時(shí)可以指定初始值,如果未指定C++會(huì)去執(zhí)行默認(rèn)初始化(default-initialization)。 那么什么是”默認(rèn)初始化”呢?
- 1.棧中的變量(函數(shù)體中的自動(dòng)變量)和堆中的變量(動(dòng)態(tài)內(nèi)存)會(huì)保有不確定的值;
- 2.全局變量和靜態(tài)變量(包括局部靜態(tài)變量)會(huì)初始化為零;
- 3.(lanyan注)函數(shù)體中的自動(dòng)變量在有些編譯器下(我的是Clion2021.3),雖然在未初始化的情況下輸出也是0,但是編譯時(shí)會(huì)出現(xiàn)警告,所以這樣寫是不對(duì)的。
所以函數(shù)體中的變量定義是這樣的規(guī)則:
//C++中 int i; // 不確定值 int i = int(); // 0 int *p = new int; // 不確定值 int *p = new int(); // 0
三、靜態(tài)和全局變量的初始化
未初始化的和初始化為零的靜態(tài)/全局變量編譯器是同樣對(duì)待的,把它們存儲(chǔ)在進(jìn)程的BSS段(這是全零的一段內(nèi)存空間)中。所以它們會(huì)被”默認(rèn)初始化”為零。
來看例子:
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 // 全局靜態(tài)變量
32767 // 局部變量
0x7fff510cfa68 // 局部指針
0 // 局部靜態(tài)變量
動(dòng)態(tài)內(nèi)存中的變量在上述代碼中沒有給出,它們和局部變量(自動(dòng)變量)具有相同的”默認(rèn)初始化”行為。
四、成員變量的初始化
成員變量分為成員對(duì)象和內(nèi)置類型成員,其中成員對(duì)象總是會(huì)被初始化的。而我們要做的就是在構(gòu)造函數(shù)中初始化其中的內(nèi)置類型成員。
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
可見內(nèi)置類型的成員變量的”默認(rèn)初始化”行為取決于所在對(duì)象的存儲(chǔ)類型,而存儲(chǔ)類型對(duì)應(yīng)的默認(rèn)初始化規(guī)則是不變的。 所以為了避免不確定的初值,通常會(huì)在構(gòu)造函數(shù)中初始化所有內(nèi)置類型的成員。
Effective C++: Item 4一文討論了如何正確地在構(gòu)造函數(shù)中初始化數(shù)據(jù)成員。
這里就不展開了,直接給出一個(gè)正確的初始化寫法:
class A{
public:
int v;
A(): v(0);
};五、封閉類嵌套成員的初始化
再來探討一下當(dāng)對(duì)象聚合發(fā)生時(shí)成員變量的”默認(rèn)初始化”行為,同樣還是只關(guān)注于基本數(shù)據(jù)類型的成員。
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;
}結(jié)果:
0 0
43224321 -1610612736
規(guī)則還是是一樣的,默認(rèn)初始化行為取決于它所屬對(duì)象的存儲(chǔ)類型。
封閉類(Enclosing)中成員對(duì)象的內(nèi)置類型成員變量的”默認(rèn)初始化”行為取決于當(dāng)前封閉類對(duì)象的存儲(chǔ)類型,而存儲(chǔ)類型對(duì)應(yīng)的默認(rèn)初始化規(guī)則仍然是不變的。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C++ using namespace std 用法深入解析
以下是對(duì)C++中using namespace std的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下2013-07-07
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋游戲
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
C++靜態(tài)成員函數(shù)不能調(diào)用非靜態(tài)成員變量(詳解)
下面小編就為大家?guī)硪黄狢++靜態(tài)成員函數(shù)不能調(diào)用非靜態(tài)成員變量(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-12-12
詳解C/C++中低耦合代碼的設(shè)計(jì)實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了C/C++?相關(guān)低耦合代碼的設(shè)計(jì)實(shí)現(xiàn),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++有一定的幫助,感興趣的小伙伴可以了解一下2023-01-01
C++實(shí)現(xiàn)簡(jiǎn)易圖書館管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡(jiǎn)易圖書館管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03

