先看一段代碼:
#include <iostream>
using namespace std;
void func(char* p) {
cout << "void func(char* p)" << endl;
cout << p << endl;
}
void func(int p) {
cout << "void func(int p)" << endl;;
cout << p << endl;
}
int main() {
//int
func(10);
//char*
func(NULL); //這裏我希望程序調用func(char* p)的函數
system("pause");
return 0;
}
輸出結果:
void func(int p)
10
void func(int p)
0
調用了兩次func(int p)函數,且按理説NULL指針是不能cout的
也就是説第二次調用func(NULL)也調用了一次func(int p) 並且傳入的p是0
原因:
在底層源碼中NULL這個宏是這樣定義的
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
也就是説如果源碼是C++程序NULL就是0,如果是C程序NULL表示(void*)0。那麼為什麼要這樣做呢? 是由於 C++ 中,void * 類型無法隱式轉換為其他類型的指針,此時使用 0 代替 ((void *)0),用於解決空指針的問題。這個0(0x0000 0000)表示的就是虛擬地址空間中的0地址,這塊地址是隻讀的。
正如:C++98/03 標準中,將一個指針初始化為空指針的方式有 2 種
char *ptr = 0;
char *ptr = NULL;
並且
int* ptr1 = NULL;
char* ptr2 = NULL;
double* ptr3 = NULL;
void* ptr4 = NULL;
int* ptr5 = ptr4;//報錯:"void*"類型的值不能用於初始化"int*"類型的實體
//是由於 C++ 中,void * 類型無法隱式轉換為其他類型的指針,此時使用 0 代替 ((void *)0),用於解決空指針的問題。
int* ptr5 = (int*)ptr4; //強轉正確不報錯
C++11引入nullptr關鍵字用於標識空指針,是std::nullptr_t類型的(constexpr)變量。它可以轉換成任何指針類型和bool布爾類型(主要是為了兼容普通指針可以作為條件判斷語句的寫法),但是不能被轉換為整數。
nullptr是專用於初始化空類型指針,不同類型的指針變量都可以使用 nullptr 來初始化,nullptr 出現的目的是為了替代 NULL
#include <iostream>
using namespace std;
void func(char* p) {
cout << "void func(char* p)" << endl;
//cout << *p << endl;
}
void func(int p) {
cout << "void func(int p)" << endl;;
//cout << p << endl;
}
int main() {
int* ptr1 = nullptr;
char* ptr2 = nullptr;
double* ptr3 = nullptr;
void* ptr4 = nullptr;
int* ptr5 = (int*)ptr4;
//int
func(10);
//char*
func(nullptr);
system("pause");
return 0;
}
輸出結果:
void func(int p)
void func(char* p)
通過輸出的結果可以看出,nullptr 無法隱式轉換為整形,但是可以隱式匹配指針類型。在 C++11 標準下,相比 NULL 和 0,使用 nullptr 初始化空指針可以令我們編寫的程序更加健壯,因此當需要使用 NULL 時候,養成直接使用 nullptr的習慣。