2016-10-29 90 views
1

這是我在這個論壇的第一個問題,對不起我的英文不好。 我有一個關於C++中的指針和動態內存的問題。用動態內存C++移動指針

實施例,這樣的代碼:

#include <iostream> 

using namespace std; 

int main(int argc, char const *argv[]) 
{ 
    int *a = new int; 

    for (int i = 0; i < 5; i++) 
    cout << a++ << endl; 

    return 0; 
} 

輸出:

0x11d4c20 
0x11d4c24 
0x11d4c28 
0x11d4c2c 
0x11d4c30 

我的問題,是我爲什麼可以移動內存大於我與new創建的 '單' 塊以上。

  • 什麼是a指向?

發生同樣與new int[],即使我具體尺寸:

#include <iostream> 

using namespace std; 

int main(int argc, char const *argv[]) 
{ 
    int *a = new int[2]; 

    for (int i = 0; i < 5; i++) 
    cout << a++ << endl; 

    return 0; 
} 

輸出:

0x2518c20 
0x2518c24 
0x2518c28 
0x2518c2c 
0x2518c30 

再次,發生了什麼?

  • 什麼是a指向?

這是否意味着我侵犯了記憶?

+1

這是一個指針,所以你可以執行指針算術。對於您是否實際上仍然指向程序員(即:您)上的有效數據,沒有任何檢查。如果你用你的指針移過已分配的內存,你正在調用未定義的行爲(你正在訪問「隨機」數據) – UnholySheep

+0

看看[這個問題](http://stackoverflow.com/questions/4998939/how-does -unary-addition-on-c-pointers-work) – ray

+0

@UnholySheep我明白指針的行爲,所以'a'只是指向「隨機」數據? –

回答

-1

C++(和c)中的指針只是內存地址(32/64位數字)。增加它們或減少你想要的任何方式都沒有問題,而且你沒有違反內存或任何其他規則。但是如果您在通過for週期後嘗試讀取或寫入A指向的地址,則會違反內存。

至於它指向的是什麼,很可能它只是由new(和malloc下)分配給您的更多空間,因爲它往往會提供比您要求的更多空間,儘管此行爲不能保證。它也可能指向堆數據或只是未分配的內存。

+0

*「最有可能的只是'new'分配給你的更多空間」* - 你認爲這是什麼? – UnholySheep

+0

_「C++中的指針(和c)只是內存的地址(32/64位數字)。」_不,不是。 –

+0

_「增加它們或減少任何方式都沒有問題,而且你沒有違反內存或任何其他規則」_這是錯誤的。增量有UB。 –

1

aint*,而不是int。你打印的內容實際上是指針,即指向對象的內存地址。每當你要修改的尖值使用引用操作*,即

cout << (*a)++ << endl; 

注:同樣,你可以得到一個指向int使用參考操作,&,不要與混淆參考(例如int&類型)。

This may print 0 1 2 3 4可能,因爲您沒有初始化在動態內存中創建的新的int。這意味着從*a(取消引用a)的閱讀是未定義的行爲,這意味着您的程序可能會行爲不當。你必須改變使用new您行:

int *a = new int(); 

這將初始化*a0現在0 1 2 3 4能夠正確打印。

請注意int *a = new int[2];確實在動態存儲器中創建了2個條目的動態數組,這意味着也可以使用*(a + 1)(就像它是常規數組一樣)。它初始化*a爲2

千萬別忘了delete a;當你使用它來完成。在實際的應用程序中,如果不這樣做,您可能會發生內存泄漏 - 即您的程序仍會使用不再需要的內存。注意,當你不得不刪除一個動態分配的數組(即new int [2])時,你需要使用delete[] a;來代替,否則你會觸發未定義的行爲。

您也可以使用C++ 11來替代這種內存分配,即unique_ptr(或shared_ptr):

#include <memory> 
// ... 
std::unique_ptr<int> a = std::make_unique<int>(0); 

由於該解決方案,你不需要delete a因爲unique_ptr會爲你做,當它自己死亡(即超出範圍,在這裏)。

編輯:獎金:

0x2518c20 
0x2518c24 
0x2518c28 

爲什麼,如果你只是使用++數量增加了4?

在地址上使用++實際上會將其增加sizeof(T),這裏是sizeof(int)而不是1。這就解釋了爲什麼如前所述,如果您使用new int[2],則可以使用*(a + 1)

+1

增量已經是UB。 –

+0

對不起,如果我沒有解釋我自己,我知道如何使用指針(區分'a'和'* a'),我的問題是'a'指向什麼?如果可以讀取和修改該塊的數據。 –

+0

'a'指向堆中分配(很可能)的內存。閱讀'* a'是合法的。讀'*(a + 1)'不是,因爲你沒有用'new'分配這個內存。 – Asu

0

我認爲這是因爲指向一個整數,一個整數的大小是4個字節(sizeof(int)== 4)執行一個++後,指向下一個整數,嘗試char * a,並且++要更加確定

+2

這是一個充其量的評論,而不是一個答案。另外'sizeof(int)'是***不保證是4 – UnholySheep

+1

沒有「下一個整數」。 –

+1

@UnholySheep:它更接近答案,不應寫在評論部分,它不受同儕審查控制。 –

0

指向對象或對象後面的點是合法的。 A new int[2]創建兩個相鄰的對象(在一個數組中)並返回一個指向第一個的指針。

所以是的,你在上面做的是不允許的。向指向單個對象的指針添加5的行爲不是由C++標準定義的;編譯器可以生成完成任何操作的程序集。

碰巧,在平面內存架構上,指針基本上是無符號整數。並且將指針遞增1只會增加指針對象的大小。

所以經常發生的是你只是指向發生在那裏的任何事情。

現在這是不能保證,不應該依靠。許多使得動作未定義的C++規則允許通過您認爲編譯器所做的「天真」映射進行某些優化。例如,指向short的指針永遠不會指向int並以定義的方式更改其值,這意味着如果某個函數同時具有指針intshort,則可以假定對short的寫入不會修改int

天真「寫在一個int這兩個詞」用短褲可以正常工作,那麼不似乎沒有任何理由的工作方法,因爲該行爲是不確定的,編譯器是免費優化假設它不可能發生

總之,你的行爲不合法,你得到的行爲並不令人意外,但你永遠不能依靠它。

指針不僅僅是無符號整數,即使這是您的編譯器實現它們。它們是抽象的。他們的行爲不是由他們的實施決定的,而是由你的標準允許你做什麼決定的。當你以標準不允許的方式行事時,你得到的行爲是不符合標準的。編譯器可以並且已知可以利用這個事實來假定未定義的行爲不能也不會發生。程序可能會在未定義行爲之前的代碼行意外行爲,因爲編譯器會根據您的代碼具有良好定義的行爲進行重新排序和優化。

+0

它是允許的和合法的,只是未定義。 –

+0

「非法」暗示「不合格」。執行未定義行爲的程序不是「非法」的,甚至不在C++範圍內;你只是不知道你會得到什麼。 –

+0

雖然兩者可能相似,但它們仍然是_two_。這種情況有未定義的行爲;它不會使程序不合格。這一點的措辭非常明確。 –