空指針也不崩潰-轉載

http://blog.sina.com.cn/s/blog_532f6e8f01017ljb.html

 

class A

{

public:

int m_iA1;

void print()

{

cout << "A" << endl;

}

};

int main()

{

A *pObjectA=NULL;

pObjectA->print();

return 0; 

}

 

*a沒有初始化,結果成功輸出“A”。

分析:成員函數在代碼段,成員變量在數據段,地址爲在類對象地址基礎上累加。

此處的print成員函數沒有用到成員變量,與類外獨立函數無異。調用的時候不涉及數據段,不會崩潰。

 

如果成員函數print中使用到了成員變量,情況會是怎樣呢?

class A

{

public:

int m_iA1;

char m_chA2;

void print()

{

m_iA1 = 1;

cout << "A" << endl;

}

};

int main()

{

A *pObjectA=NULL;

pObjectA->print();

return 0; 

}

編譯執行後,崩在了print函數中的紅色標記語句。

分析:此處的print成員函數用到成員變量m_iA1,我們可以看到,&pObjectA=0x00000000,&m_iA1=0x00000000,&m_iA2=0x00000004

空指針也不崩潰
訪問了非法地址,崩潰了

 

嘗試給pObjectA分配空間後,&pObjectA=0x003b6060,&m_iA1=0x003b6060,&m_iA2=0x003b6064,

空指針也不崩潰

這是合法的數據段地址,訪問成功。

 

我們再給A類加一點有趣的東西來驗證一下

1、static靜態變量

class A

{

public:

static int m_iSA4;

static void print()

{

m_iSA4 = 4;

cout << "A" << endl;

}

};

int A::m_iSA4 = 0;

 

int main()

{

A *pObjectA=NULL;

pObjectA->print();

return 0; 

}

 

運行成功!靜態變量獨立於類外部分配好了合法地址,訪問成功。

 

2、繼承

class B

{

int m_iB1;

public:

virtual void print()

{

cout << "B" << endl;

}

};

 

class A:public B

{

    int m_iA1;

    char m_chA2;

public:

    void print()

    {

        cout << "A" << endl;

    }

};

 

int main()

{

    A *pObjectA=NULL;

    pObjectA->print();

    return 0; 

}

 

運行之後崩在在main函數的紅色標記語句。

分析:雖然A類的print函數沒有用到顯式的成員變量,但是類A繼承於類B,print()是繼承於B的虛函數,調用A的print函數時,用到了虛表,虛表地址在類對象數據段最開頭,此時訪問了非法地址。

可以看到成員變量地址:

空指針也不崩潰
 

給pObjectA分配空間之後再看

空指針也不崩潰
 

可以看到,在繼承類對象的地址空間中的順序爲:虛表指針、基類成員變量、繼承類成員變量

 

通常崩潰報錯的對話框中會給出一些關鍵信息:

空指針也不崩潰
如此圖中的0x00411596表示出錯的代碼段地址,0xC0000000爲出錯的數據段地址,0xC0000005爲錯誤碼。“Access violation”就是此錯誤碼的具體含義,查看所有錯誤碼含義可查閱Visual Studio-Debug-Exceptions-Win32 Exceptions。詳細錯誤信息都會保存在dmp文件中,用Windbg這類工具可以看到詳細信息,進行具體分析。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章