走進C++:C到C++的過渡

目錄

什么是C++呢?

C++的發展史

多了一些吃前來很香的“語法糖”。

語法糖一:命名空間

命名空間有個強大的功能

如何使用

語法糖二:缺省參數

語法糖三:函數重載

語法糖四:引用????????

引用傳參

引用返回

引用和指針的不同點:

語法糖五:內聯函數

內聯函數相比于普通函數的特性

語法糖六:auto關鍵字(C++11)

auto的使用規則

語法糖七:基于范圍的for循環(C++11)

范圍for的語法

范圍for的使用條件

語法八:指針空值nullptr(C++11)


什么是C++呢?

先官方的解釋一下:

C語言是結構化和模塊化的語言,適合處理較小規模的程序。對于復雜的問題,規模較大的程序,需要高度的抽象和建模時,C語言則不合適。

為了解決軟件危機, 20世紀80年代, 計算機界提出了OOP(objectoriented programming:面向對象)思想,支持面向對象的程序設計語言應運而生。
?1982年,Bjarne Stroustrup博士在C語言的基礎上引入并擴充了面向對象的概念,發明了一種新的程序語言。為了表達該語言與C語言的淵源關系,命名為C++。

因此:C++是基于C語言而產生的,它既可以進行C語言的過程化程序設計,又可以進行以抽象數據類型為特點的基于對象的程序設計,還可以進行面向對象的程序設計。

簡而言之:

C++就是本賈尼大佬看不慣C語言,想要創造一門用起來更爽的語言,因此創造了C++。

同時C++也是包含C語言的,因此C語言的所有語法在C++都能使用。

看這位大佬的發量,就大體明白,C++也不是容易搞明白的,因此本文將帶你利用C語言的基礎,走進C++。

C++的發展史

雖然本賈尼是C++之父,但是C++的發展卻不只是犧牲了這位大佬的“發際線”,當然還有其他大佬……

  1. C with classes(C++前身):引入了類及派生類、公有和私有成員、類的構造和析構、友元、內聯函數、賦值運算符重載等特性。
  2. C++1.0:增加了虛函數概念,支持函數和運算符的重載,以及引用和常量等。
  3. C++2.0:提供了面向對象編程的支持,包括保護成員、多重繼承、對象的初始化和抽象類、靜態成員等。
  4. C++3.0:進一步完善了面向對象特性,引入了模板技術來解決多重繼承產生的二義性問題。
  5. C++98:作為第一個官方發布的C++標準版本,得到了廣泛的支持,并引入了STL(標準模板庫)。
  6. C++03:對語言特性進行了小幅修訂,主要是為了減少多異性。
  7. C++05:引入了TR1,正式更名為C++0x,增加了許多新特性,如正則表達式、基于范圍的for循環等。
  8. C++11:引入了許多革命性的新特性,如lambda表達式、auto類型推導、標準線程庫等,使C++更像一門現代語言。
  9. C++14:修復了C++11中的漏洞,并增加了新的特性,如泛型lambda表達式、二進制字面常量等。
  10. C++17:在C++11的基礎上做了改進,增加了19個新特性,包括static_assert()、Fold表達式等。
  11. C++20:這是自C++11以來最大的發行版,引入了模塊、協程、范圍、概念等特性,并對已有特性進行了更新。
  12. C++23:目前正在制定中,預計會進一步擴展和優化C++語言的功能。

總的來說,C++語言從最初的C with classes發展到現在的C++23,歷經多次迭代和更新,不斷豐富和完善其功能,使其成為了一門強大而靈活的高級編程語言。

為什么要學習C++

C++是目前市面上使用最多的語言之一,C/C++一直在語言界穩居前三。

對于操作系統、嵌入式開發、服務端開發、游戲開發,都需要大量的使用C++,因此學習C++非常有必要。

言歸正傳,下面進入C++的正式學習。

開篇就提到,C++相比于C語言是用起來很“爽”的語言,為什么真么說呢,主要是C++補充了C語言的一些語法,可以理解為:

多了一些吃前來很香的“語法糖”

語法糖一:命名空間

當我們寫一些大型的C語言項目時,大量的變量命名常常會搞得我們頭昏腦脹,不會命名、命名沖突,導致語法錯誤頻出,C++便引入了第一個語法糖:命名空間

對于C語言的函數,變量的命名我們已經很熟悉,那么C++是如何命名的呢?答案是借助一個關鍵字:namespace。namespace顧名思義就是命名空間的意思,因此namespace可以創建一個命名空間。

舉例:

namespace XXX
{int x = 0;double y = 0.0;
}

為了防止命名沖突,我們將變x、y放在命名空間XXX中。需要注意的是,一個獨立的命名空間,花括號的尾部不能有分號!

命名空間有個強大的功能

在C++中,命名空間(namespace)是一種將代碼組織成邏輯塊的機制,它可以包含類、函數、變量、模板、類型別名等。命名空間的主要目的是提供一種組織代碼的方式,以避免命名沖突,尤其是在大型項目中或者當多個庫被一起使用時。

類、函數、變量、模板、類型別名,都可以包含在命名空間中。同時命名空間可以套用命名空間。

如何使用

有了命名空間之后,我們該如何使用命名空間的內容呢?

namespace Test
{int test = 10;int Add(int a, int b){return a + b;}
}

我們依靠的是一個操作符:域作用限定符 ::

為什么是域作用限定符呢?“域”即是區域,只要被花括號{ }括起來的空間,都可以看作一塊域,訪問命名空間,需要使用 ::限定符。

三大使用方式

以Test為例

方式一:將命名空間全部展開。

展開是一種授權,授權可以去對應的命名空間查找內部成員。具體實現為using namespace Test;


namespace Test
{int test = 10;int Add(int a, int b){return a + b;}
}using namespace Test;	//展開命名空間的所有元素int main()
{printf("%d\n", test);return 0;
}

test變量屬于Test命名空間,當展開Test命名空間之后,就可以訪問內部成員。

但是,將命名空間全部展開也是一種危險的行為

namespace Test
{
?? ?int test = 10;

?? ?int Add(int a, int b)
?? ?{
?? ??? ?return a + b;
?? ?}
}

int test = 81;

using namespace Test;

見此代碼,當test函數在全局與Test中同時定義時,就會出現命名沖突。因此無論哪種展開方式(包含下面的方案),展開都不應該出現命名沖突。

方法二:將部分成員展開。

具體實現是using Test :: test;表示展開Test空間中的test變量。using + 空間名字 :: 成員名字。此時仍然可以直接訪問test。

方法三:直接在使用處展開。

格式: 命名空間 :: 成員

namespace Test
{int test = 10;int Add(int a, int b){return a + b;}
}// ::域作用限定符int test = 81;int main()
{printf("%d\n", Test::test);return 0;
}

雖然出現兩個test,但是在使用處直接引用,就可以限定去Test空間尋找test變量,而不是去全局。

在工程中,常用的符號一般采用第二種展開方式,不常用的用第三種。

對于C++,有一個標準命名空間,叫做std,常用的函數都在std中。

在C++中,輸出用cout,輸入用cin,換行用endl,這些都定義在std中。

#include <iostream> using std::cout;
using std::cin;
using std::endl;int main()
{int i = 0;cin >> i;cout << i << endl;return 0;
}

<< 流插入運算符 , >>是流提取運算符

那為什么引用頭文件之后,還得展開命名空間呢?

下面是比較標準的解釋:

在C++中,cout?是?iostream?庫?? 中定義的一個對象,用于輸出數據到標準輸出(通常是終端或控制臺)。iostream?庫定義在?std?命名空間中。命名空間是一種將庫名字封裝起來的方法,以避免不同庫中可能存在的名字沖突。

當您在程序中包含?<iostream>?頭文件時,您實際上是包含了?iostream?庫的所有聲明。然而,默認情況下,這些聲明都是在?std?命名空間之內的。因此,如果您直接使用?cout?而不指明它屬于?std?命名空間,編譯器將不知道您所指的?cout?是?std?命名空間中的?cout。

語法糖二:缺省參數

缺省是默認的意思,缺省參數就是指默認的參數,對于C++函數,可以給形參創建一些缺省值,使之成為缺省參數。

缺省參數是聲明或定義函數時為函數的參數指定一個缺省值。在調用該函數時,如果沒有指定實
參則采用該形參的缺省值,否則使用指定的實參。
舉例:
#include <iostream> using std::cout;
using std::cin;
using std::endl;void Date(int year = 2024, int month = 5, int day = 9)
{cout << year << " " << month << " " << day << endl;
}int main()
{Date(2022, 11, 13);Date();return 0;
}

對于Date函數,給定了一些缺省參數。

程序運行結果:

2022 11 13
2024 5 9

當傳參時,打印結果是參數結果;不傳參時,打印結果是缺省結果。

同時缺省還分為全缺省和半缺省。全缺省是指將所有參數都設置為缺省參數;半缺省是指將部分參數設置為缺省參數,但是半缺省有一定規則:參數必須從右往左缺省,且中間不能跳過參數。

多提一嘴,函數的定義應該聲明與定義分離,如果定義在頭文件中,那包含頭文件時,會同時在符號表存在多個函數符號,出現符號沖突,連接錯誤。

缺省函數應該在聲明時給出缺省參數,而不是定義時,原因如下:

缺省參數通常在函數原型(函數聲明)中給出,而不是在函數定義中。函數原型通常位于頭文件中,而函數定義位于源文件中。這樣做的好處是,你可以確保無論函數在哪里被調用,調用者都能看到缺省參數的值。

總結一些缺省的注意點:

1. 半缺省參數必須從右往左依次來給出,不能間隔著給
void Func(int a, int b = 10, int c = 20)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}

2. 缺省參數不能在函數聲明和定義中同時出現,一般在聲明處給出。
//a.h
void Func ( int a = 10 );
// a.cpp
void Func ( int a = 20 )
{}
// 注意:如果生命與定義位置同時出現,恰巧兩個位置提供的值不同,那編譯器就無法確定到底該
用那個缺省值
3. 缺省值必須是常量或者全局變量
4. C語言不支持(編譯器不支持)

語法糖三:函數重載

函數重載真是C++最甜的語法糖之一了,通過對比C與C++,就可以得知。

講解函數重載之前,先講一個笑話,這個笑話就體現了函數重載的思想。

NBA的球員,Lebron曾經在一場比賽中投出10中9的優秀命中率,因此球迷樂呵到“出手十次,一次不進”的笑話。大家可以細細品一品“一次不進”這句話。

函數重載:是函數的一種特殊情況,C++允許在同一作用域中聲明幾個功能類似的同名函數,這
些同名函數的形參列表(參數個數 或 類型 或 類型順序)不同,常用來處理實現功能類似數據類型
不同的問題。
簡而言之,函數重載就是: 函數名相同,參數不同,從而導致功能不同。同時,重載一定是出現在同一作用域。
下面就從Swap函數的實現進行入門講解。
C語言對于Swap的實現:
void SwapInt(int* pa, int* pb)
{int tmp = *pa;*pa = *pb;*pb = tmp;
}void SwapChar(char* pa, char* pb)
{char tmp = *pa;*pa = *pb;*pb = tmp;
}

在使用時:

int main()
{int a = 10;int b = 2;SwapInt(&a, &b);char m = 'a';char f = 'b';SwapChar(&m, &f);return 0;
}

C++對于swap的實現:


void Swap(int* pa, int* pb)
{int tmp = *pa;*pa = *pb;*pb = tmp;
}void Swap(char* pa, char* pb)
{char tmp = *pa;*pa = *pb;*pb = tmp;
}
int main()
{int a = 10;int b = 2;Swap(&a, &b);cout << a << " " << b << endl;char m = 'a';char f = 'b';Swap(&m, &f);cout << m << " " << f << endl;return 0;
}

可以看到,可以直接使用相同的函數名字,對于不同的參數,函數可以自己去匹配類型。

但是注意函數重載與函數缺省參數同時使用時的沖突問題。

那為什么C不支持函數重載,但是C++支持呢?

那就要從程序的運行階段去分析了。程序的運行階段分為:與處理、編譯、匯編、鏈接,四個階段。

在編譯時,會進行符號匯總;匯編會生成符號表;鏈接會對符號表進行合并與重定位。對于C語言,函數名在生成符號時,往往只是直接利用函數名作為符號,或者只是進行簡單的修飾,因此函數名不能沖突;但是C++卻有一套“獨特的命名規則”,這種命名規則叫做名字修飾(name Mangling)。同時名字修飾也是支持重載的原理。

在Linux下,gcc編譯器可以很明顯的觀察到函數符號的名字修飾規則:

【_Z+函數長度+函數名+類型首字母】

因此構成函數重載時,“類型首字母”的不同,也構成了符號表中符號的不同,不至于在鏈接階段出現鏈接錯誤。

語法糖四:引用????????

先解釋下何為引用,引用就是“取別名”。舉個例子,國足因為在球場的拉跨表現,被球迷人稱為“海參隊”,海參隊就是球迷們對國足的別稱。

引用概念
引用不是新定義一個變量,而是給已存在變量取了一個別名,編譯器不會為引用變量開辟內存空
間,它和它引用的變量共用同一塊內存空間。
在使用引用時,有以下公式:
類型& 引用變量名(對象名) = 引用實體;
int main()
{int a = 10;int& b = a;cout << b << endl;return 0;
}

b就是a的一個引用變量,可以理解為b就是a的“別名”,對b進行操作,就可以控制a

int main()
{int a = 10;int& b = a;++b;cout << a << endl;    //打印11return 0;
}
注意: 引用類型 必須和引用 實體 同種類型 的。
引用特性
1. 引用在 定義時必須初始化
2. 一個變量可以有多個引用
3. 引用一旦引用一個實體,再不能引用其他實體
常引用
觀察以下代碼,反映了幾個情況。
const int a = 10;
int& b = a;
const int a = 10;
?? ?const int& b = a;
int a = 10;
?? ?const int& b = a;
需要注意的是,①存在語法錯誤,因為出現了“權限擴大”。在引用時,權限:可以縮小、平移,但是不能放大。

int a = 0;
int func()
{a = 3;return a;
}int main()
{int b = func();return 0;
}

這段代碼的意思是用b接收返回值,b接收的是數值的拷貝。

int a = 0;
int func()
{a = 3;return a;
}int main()
{const int& b = func();return 0;
}

這段代碼表示用b作為引用變量,接收函數的返回值,引用變量b是a的一個別稱,可以指向這塊空間。但是為什么b需要被const修飾呢?

這是因為函數在返回的時候,會將返回值傳遞給一個臨時的對象,但是引用不能直接綁定到臨時對象上(臨時對象的生命周期極短),為了防止引用懸空,通常會將引用變量用const修飾,此時這個臨時對象的生命周期也會變長。

引用變量的兩種應用

引用傳參

引用傳參是指用引用變量作為形參,接收實參。再拿Swap函數舉例。


void Swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}int main()
{int a = 3, b = 5;Swap(a, b);cout << a << " " << b << endl;return 0;
}

既然引用變量只是一個別名,可以指向“本體”,那邊可以用引用變量接收形參,進而修改實參。

引用返回

引用返回是利用引用變量接收引用返回。

先看一段傳值返回的代碼

int Func()
{int n = 3;return n;
}int main()
{int a = Func();return 0;
}

a的值是多少呢?a = 3,其過程是,先將n傳給一個臨時的對象,a再接收臨時對象的值。

傳值返回用值接收

再看引用返回的代碼

int& Add(int x, int y)
{int z = x + y;return z;
}int main()
{int& a = Add(3, 5);Add(2, 2);cout << a << endl;	// 打印 4 return 0;
}

引用返回是用引用變量接收函數的返回值(返回類型之后需要加一個&,表示引用返回),傳引用返回用引用變量接收

為什么a的值是4不是8呢?這就要從函數棧幀的創建于銷毀入手。
第一次調用Add函數時
函數在調用完成之后,Add棧幀銷毀
第二次調用Add時
可以看到,第二次調用Add時,其棧幀覆蓋了第一次調用時的棧幀,而 a只是一個指向“返回空間”
的別稱,當第二次調用之后,返回空間中的值被修改,自然a就被修改。
這就有點類似于C語言的野指針問題了。舉個例子,當你不住酒店,退房完成之后,此時在道理上你沒有訪問這間房間的權限,但是你留了一張房卡,沒有退回去,這時候就出現了非法訪問的問題,即野指針。假如你之前在房間的抽屜里面放了一個蘋果,那你再進去的時候,你還能保證房間還有蘋果嗎?(薛定諤的貓)
同理轉移到Add函數上,當你第二次使用Add函數時,由于a作為引用變量,指向的是一塊已經銷毀的空間,此時再度訪問這塊空間之后,就不能保證a的值不發生改變。
那正確的引用返回應該是怎樣使用的呢?為了防止出現非法的空間,引用返回返回的變量必須是一個出了函數還不會銷毀的變量(static修飾、malloc在堆區、全局變量、引用傳參的對象)。對于形參用引用傳參時,返回的引用參數一直在外部是存在的,可以使用。

C++中int& 函數利用引用返回時,只能使用引用變量接收嗎

在C++中,使用引用作為函數返回類型時,通常情況下,返回的是某個變量的別名,而不是一個獨立的變量。因此,通常你確實需要使用一個引用變量來接收這個返回值,以便于直接對原始變量進行操作。

因此,在使用引用返回時,一定要注意返回變量會不會出函數留存。

引用傳參與引用返回的優點

引用傳參(何時都可以使用)

1.提高函數效率

2.輸出型參數的修改(如力扣題目returnSize的修改)

引用返回(出函數對象的作用還在,方可使用)

1.提高效率

2.修改返回對象。

看到這里,你或許會疑問,怎么引用與指針如此相似,引用在語法上不會占用空間,其實引用在底層和指針都是一樣的。

引用與指針好比是大眾與保時捷,在很多時候,往往保時捷的發動機等配置與大眾是一樣的,只不過在外部的外觀不一樣。

引用和指針的不同點:

1. 引用概念上定義一個變量的別名,指針存儲一個變量地址。

2. 引用在定義時必須初始化,指針沒有要求

3.引用在初始化時引用一個實體后,就不能再引用其他實體,而指針可以在任何時候指向任何

一個同類型實體

4. 沒有NULL引用,但有NULL指針

5. 在sizeof中含義不同:引用結果為引用類型的大小,但指針始終是地址空間所占字節個數(32

位平臺下占4個字節)

6. 引用自加即引用的實體增加1,指針自加即指針向后偏移一個類型的大小

7. 有多級指針,但是沒有多級引用

8. 訪問實體方式不同,指針需要顯式解引用,引用編譯器自己處理

9. 引用比指針使用起來相對更安全

語法糖五:內聯函數

C++們在使用C語言的宏時,發現了宏(宏常量、宏函數)有大量的弊端:

1.沒有安全類型的檢查

2.不能調試(預處理階段被替換)

3.可維護性差

因此內聯函數便繼承了宏的優點:

1.具有復用性

2.不需要棧幀的建立(針對頻繁調用的小函數),效率高

同時拒絕了宏的弊端,應運而生。

內聯函數的概念

inline修飾的函數叫做內聯函數,編譯時C++編譯器會在調用內聯函數的地方展開,沒有函數調
用建立棧幀的開銷,內聯函數提升程序運行的效率。
inline是C++的一個新的關鍵字,用來聲明內聯函數。
inline int Add(int x, int y)
{int z = x + y;return z;
}int main()
{int a = Add(3, 5);	cout << a << endl;	//打印8return 0;
}

這便是一個內聯函數的使用。那內聯函數和普通函數有什么區別呢?當然有區別,內聯函數不需要建立棧幀,而是在使用的地方直接展開。

可以看到P1不是內聯函數,因此有call指令,而call指令就是轉到對應函數建立棧幀的標志。

內聯函數相比于普通函數的特性

1. inline是一種以空間換時間的做法,如果編譯器將函數當成內聯函數處理,在編譯階段,會
用函數體替換函數調用,缺陷:可能會使目標文件變大(代碼膨脹)優勢:少了調用開銷,提高程序運 行效率。
2.inline對于編譯器而言只是一個建議,不同編譯器關于inline實現機制可能不同,一般建
議:將函數規模較小(即函數不是很長,具體沒有準確的說法,取決于編譯器內部實現)、
是遞歸、且頻繁調用的函數采用inline修飾,否則編譯器會忽略inline特性。
下圖為 《C++prime》第五版關于inline的建議:
3. 內聯函數不可以聲明定義分離!因為內聯函數會在使用的地方直接展開,在符號表中不會存在有效地址,鏈接時,無法找到對應有效地址。一般都會定義在頭文件中。

C++有哪些技術替代宏?

1. 常量定義 換用const enum

2. 短小函數定義 換用內聯函數

語法糖六:auto關鍵字(C++11)

C++程序在書寫一些大型的項目時,類型名常會復雜冗長,因此auto關鍵字應運而生,這個關鍵字的能力是根據變量,自動識別變量的類型。
在早期C/C++中auto的含義是:使用auto修飾的變量,是具有自動存儲器的局部變量,但遺憾的
是一直沒有人去使用它。C++11中,標準委員會賦予了auto全新的含義即:auto不再是一個存儲類型指示符,而是作為一個新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時期推導而得。由此開始,auto關鍵詞變成了一個香餑餑。
int TestAuto()
{
return 10;
}
int main()
{int a = 10;auto b = a;auto c = 'a';auto d = TestAuto();cout << typeid(b).name() << endl;    //打印變量的類型typeid(參數).name()cout << typeid(c).name() << endl;    cout << typeid(d).name() << endl;//auto e; 無法通過編譯,使用auto定義變量時必須對其進行初始化return 0;
}
【注意】
使用auto定義變量時必須對其進行初始化,在編譯階段編譯器需要根據初始化表達式來推導auto
的實際類型因此auto并非是一種“類型”的聲明,而是一個類型聲明時的“占位符”,編譯器在編
譯期會將auto替換為變量實際的類型

auto的使用規則

1.對于指針、引用類型的使用
用auto聲明指針類型時,用auto和auto*沒有任何區別,但用auto聲明引用類型時則必須 加&

int main()
{int x = 10;auto a = &x;	auto* b = &x;	//等價上一行auto& c = x;cout << typeid(a).name() << endl;cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;*a = 20;*b = 30;c = 40;cout << x << endl;return 0;
}

2.在同一行定義多個變量

當在同一行聲明多個變量時,這些變量必須是相同的類型,否則編譯器將會報錯,因為編譯
器實際只對第一個類型進行推導,然后用推導出來的類型定義其他變量
void TestAuto ()
{
auto a = 1 , b = 2 ;
auto c = 3 , d = 4.0 ; ? // 該行代碼會編譯失敗,因為 c d 的初始化表達式類型不同
}
3.auto 不能推導的場景
auto不能作為函數形參的類型
// 此處代碼編譯失敗, auto 不能作為形參類型,因為編譯器無法對 a 的實際類型進行推導
void TestAuto ( auto a )
{}
auto不能聲明數組
void TestAuto ()
{
int a [] = { 1 , 2 , 3 };
auto b [] = { 4 5 6 };
}
為了避免與C++98中的auto發生混淆,C++11只保留了auto作為類型指示符的用法

語法糖七:基于范圍的for循環(C++11)

范圍for的語法

在C++98中如果要遍歷一個數組,可以按照以下方式進行:
void TestFor ()
{
????????int array [] = { 1 , 2 , 3 , 4 , 5 };
????????for ( int i = 0 ; i < sizeof ( array ) / sizeof ( array [ 0 ]); ++ i )
array [ i ] *= 2 ;
????????for ( int* p = array ; p < array + sizeof ( array ) / sizeof ( array [ 0 ]); ++ p )
cout << * p << endl ;
}
對于C++11,范圍for的出現, for循環后的括號由冒號“ :”分為兩部分:第一部分是范
圍內用于迭代的變量,第二部分則表示被迭代的范圍(數組名)
簡而言之: 迭代變量 ?:迭代范圍
此時再去遍歷數組,便可用以下方式。
int main()
{int array[] = { 1, 2, 3, 4, 5 };for (auto& m : array)	//此處用引用變量 m ,去不斷指向數組中的元素。m *= 2;for (auto m : array)cout << m << " ";cout << endl;return 0;
}

此處必須用引用變量,才能修改數組的元素,&不能漏掉。這也是auto語法的常用場景。

范圍for的強大之處是:1.自動迭代 2.自動判斷結束

范圍for的使用條件

1. for循環迭代的范圍必須是確定的
對于數組而言,就是數組中第一個元素和最后一個元素的范圍;對于類而言,應該提供
begin和end的方法,begin和end就是for循環迭代的范圍。
注意:以下代碼就有問題,因為for的范圍不確定
void TestFor ( int array [])
{
for ( auto & e : array )
cout << e << endl ;
}
因為在函數形參中,不存在數組的概念,因此范圍不明。
2. 迭代的對象要實現++和==的操作。(后序的知識)

語法八:指針空值nullptr(C++11)

可以看到,這并不是一顆語法糖,而是吃糖吃多了,吃出蛀牙了,此處是填坑。

C++98 中的指針空值
在良好的C/C++編程習慣中,聲明一個變量時最好給該變量一個合適的初始值,否則可能會出現
不可預料的錯誤,比如未初始化的指針。如果一個指針沒有合法的指向,我們基本都是按照如下
方式對其進行初始化:
void TestPtr ()
{
int* p1 = NULL ;
int* p2 = 0 ;
// ……
}
NULL實際是一個宏,在傳統的C頭文件(stddef.h)中,可以看到如下代碼

#ifndef NULL
#ifdef __cplusplus
#define NULL ? 0
#else
#define NULL ? ((void *)0)
#endif
#endif
可以看到,C++而言將NULL定義為數字0,但是C卻將NULL定義為指針類型的0,因此在很多地方出現了不良的錯誤。所以需要填補C++的坑。因此nullptr便出現了。
在C++98中,字面常量0既可以是一個整形數字,也可以是無類型的指針(void*)常量,但是編譯器
默認情況下將其看成是一個整形常量,如果要將其按照指針方式來使用,必須對其進行強轉(void
*)0。
注意:
1. 在使用nullptr表示指針空值時,不需要包含頭文件,因為nullptr是C++11作為 新關鍵字 引入
2. 在C++11中,sizeof(nullptr) 與 sizeof((void*)0)所占的字節數相同。
3. 為了提高代碼的健壯性,在后續表 示指針空值時建議最好使用nullptr

以上便是C++發出的語法糖,學完之后,你覺得香不香?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/9793.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/9793.shtml
英文地址,請注明出處:http://en.pswp.cn/web/9793.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【ZZULIOJ】1100: 求組合數(函數專題)(Java)

目錄 題目描述 輸入 輸出 樣例輸入 Copy 樣例輸出 Copy 提示 code 題目描述 馬上要舉辦新生程序設計競賽了&#xff0c;與以往不同的是&#xff0c;本次比賽以班為單位&#xff0c;為了全面衡量一個班級的整體水平&#xff0c;要求從一個班的m位同學中任選k位同學代表本…

Android GPU渲染SurfaceFlinger合成RenderThread的dequeueBuffer/queueBuffer與fence機制(2)

Android GPU渲染SurfaceFlinger合成RenderThread的dequeueBuffer/queueBuffer與fence機制&#xff08;2&#xff09; 計算fps幀率 用 adb shell dumpsys SurfaceFlinger --list 查詢當前的SurfaceView&#xff0c;然后有好多行&#xff0c;再把要查詢的行內容完整的傳給 ad…

算法訓練Day35 | ● 343. 整數拆分 ● 96.不同的二叉搜索樹

343. 整數拆分 class Solution { public:int integerBreak(int n) {vector<int> dp(n1, 0);dp[2] 1;for(int i3; i<n1; i){for(int j 1; j<i/2; j){dp[i] max(dp[i], max(j*(i-j), j*dp[i-j]));}}return dp[n];} };參考文章&#xff1a;代碼隨想錄-343. 整數拆分…

找不到msvcp140.dll無法執行代碼的原因分析及修復方法

當用戶在嘗試運行某些應用程序或游戲時&#xff0c;可能會遇到系統彈出錯誤提示&#xff0c;顯示“找不到msvcp140.dll無法執行代碼”這一錯誤信息&#xff0c;它會導致程序無法正常啟動。為了解決這個問題&#xff0c;我經過多次嘗試和總結&#xff0c;找到了以下五種解決方法…

hadoop啟動后沒有namenode,datanode等解決方法

之前用的是虛擬機&#xff0c;在虛擬機上安裝的hadoop&#xff0c;但是后來&#xff0c;電腦恢復出廠設置了&#xff0c;什么都重新開始。就在本地安裝 Linux 子系統。 但是&#xff0c;有時候start-dfs.sh后&#xff0c;jps出現錯誤。 像這種拒絕連接 解決辦法就是如下&…

我的創作紀念日1460天(4年)

機緣 作為一名技術愛好者&#xff0c;我最初成為創作者的初心源于對知識的渴望和對分享的熱情。在參與多個實戰項目的過程中&#xff0c;我積累了豐富的經驗&#xff0c;這些經驗不僅僅是代碼和解決方案&#xff0c;更多的是對問題本質的理解和解決問題的思維方式。我意識到&a…

題目----力扣--移除鏈表元素

題目 給你一個鏈表的頭節點 head 和一個整數 val &#xff0c;請你刪除鏈表中所有滿足 Node.val val 的節點&#xff0c;并返回 新的頭節點 。 示例 1&#xff1a; 輸入&#xff1a;head [1,2,6,3,4,5,6], val 6 輸出&#xff1a;[1,2,3,4,5]示例 2&#xff1a; 輸入&…

如何編譯不同目錄下的兩個文件

1.直接編譯 2.打包成動靜態庫進行鏈接

【智能優化算法】蜜獾優化算法(Honey Badger Algorithm,HBA)

蜜獾優化算法(Honey Badger Algorithm,HBA)是期刊“MATHEMATICS AND COMPUTERS IN SIMULATION”&#xff08;IF 3.6&#xff09;的2022年智能優化算法 01.引言 蜜獾優化算法(Honey Badger Algorithm,HBA)受蜜獾智能覓食行為的啟發&#xff0c;從數學上發展出一種求解優化問題的…

【AMBA Bus ACE 總線 9 -- Non-cache IO device】

請閱讀【AMBA Bus ACE 總線與Cache 專欄 】 歡迎學習:【嵌入式開發學習必備專欄】 文章目錄 ACE Non-cache IO device非緩存I/O的工作原理在ARM中配置非緩存I/O示例場景Non-cache IO device Cache 訪問ACE Non-cache IO device 在ARM架構中,ACE(AXI Coherency Extension,…

Flask 統一攔截器

import osfrom flask import Flask, request, sessionapp Flask(__name__) app.config[SECRET_KEY] os.urandom(24) # 生成24位的隨機數種子&#xff0c;用于產生SESSION IDapp.route(/article/<int:article_id>) def test(article_id):"""路由地址參數…

變量的細節

如何打印不同類型的整數常量 相似于我們需要去聲明類型 public class Var {public static void main(String[] args) {// 1就是int類型常量System.out.println(1);// 120后面加一個L(l)表示他是一個long型的整數System.out.println(120l);} }如何打印不同類型的浮點數常量 與…

解決電腦睡眠后,主機ping不通VMware虛擬機

文章目錄 問題解決方法方法一方法二注意 問題 原因&#xff1a;電腦休眠一段時間&#xff0c;再次打開電腦就ping不通VMware虛擬機。 解決方法 方法一 重啟電腦即可&#xff0c;凡是遇到電腦有毛病&#xff0c;重啟能解決90%問題。但是重啟電腦比較慢&#xff0c;而且重啟…

C++用類模板封裝容器

要實現輸出不同容器的值&#xff0c;且各容器包含的數據類型也不同&#xff0c;可以使用類模板和函數模板來實現。 示例代碼如下&#xff1a; #include <iostream> #include <vector> #include <list>template <typename T> class Container { privat…

算法訓練Day36 | ● 01背包問題 ● 416. 分割等和子集

01背包問題 #include<iostream> #include<vector> using namespace std;int main(){int M;int N;cin>>M>>N;vector<int> weight(M, 0);vector<int> value(M, 0);for(int i0; i<M; i){cin>>weight[i];}for(int i0; i<M; i){ci…

Web3工具集合 - 00

使用 React 和 Material-UI 構建的 Web3 工具集合 大家好&#xff01; 我很高興向大家介紹我最近剛啟動了一個項目&#xff1a;Web3 工具集合。 這個項目的目的是一個集成各種 Web3 工具的網站&#xff0c;旨在為開發人員和加密貨幣愛好者提供便捷的工具和資源。 特點&#…

基于SSM的文化遺產的保護與旅游開發系統(有報告)。Javaee項目。ssm項目。

演示視頻&#xff1a; 基于SSM的文化遺產的保護與旅游開發系統&#xff08;有報告&#xff09;。Javaee項目。ssm項目。 項目介紹&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三層體系結構&#xff0c;…

基于ESP32和ESP8266的物聯網開發過程(二)

在做這個項目前&#xff0c;也做了一些調研。項目的初衷是想要用于智能家居。我比較了小米IoT、阿里云、ESPHOME、巴沙云、點燈科技和ONENET等幾個平臺。最終選擇了Onenet&#xff0c;部分原因是之前用過它的多協議版本&#xff0c;但現在這個版本已經下線了。 小米IoT的公測名…

C++ 類和對象:面向對象編程基礎

目錄標題 1. 什么是類&#xff1f;2. 什么是對象&#xff1f;3. 如何定義一個類&#xff1f;4. 如何創建對象&#xff1f;5. 類的構造函數6. 類的析構函數7. 數據封裝和訪問修飾符8. 示例&#xff1a;一個簡單的BankAccount類9. 使用g編譯10. 再來一個簡單的C程序11. 定義書籍類…

Linux修煉之路之初識操作系統+基礎指令(1)

目錄 引言 一&#xff1a;對操作系統(OS)的簡單了解 1.操作系統(OS) 是什么 2.操作系統好壞的衡量標準 3.操作系統存在的重要性 4.理解所有在計算機上的操作 二&#xff1a;Linux與windows操作的特點區別 三&#xff1a;基礎指令 1.ls 指令 1.使用 2.常用選項 2.…