2010-02-08 130 views
5

tl; dr - 請您在下面的第一個代碼片段中展開4條評論?具體是什麼意思derefC/C++指針問題

我是一個很長時間的Java開發人員,希望學習C++。我遇到了針對開發者的this website

int x, *p, *q; 
    p = new int; 
    cin >> x; 
    if (x > 0) q = &x; 
    *q = 3;     // 1. deref of possibly uninitialized ptr q 
    q = p; 
    p = new int;   // 2. potential storage leak (if x != 0 this 
          //  memory will not be returned to free storage) 
    *p = 5; 
    delete q; 
    *q = 1;     // 3. deref of deleted ptr q 
    q = p; 
    if (x == 0) delete q; 
    (*p)++;     // 4. deref of possibly dangling ptr p (if x is zero) 

儘管我認爲我理解指針是如何工作的,但我發現這些註釋很難理解。

我把;

  1. 我們要麼分配X(& *當然Q)在3或當q!= & X則Q有一個公正的價值,因爲它是未初始化的,我們剛纔隨機分配的一塊內存到值3.我不確定如何解引用未初始化的東西?
  2. 這很好
  3. 取消引用已刪除的指針有什麼問題?在'刪除q'之後* q是無意義的?
  4. 懸掛指針有什麼問題?即使我們仍然有指向它的指針,現在我們已經刪除了它,內存是否可以重新分配?

我想我的基本誤解是關於只是聲明一個int指針,這是否也分配內存?它是堆棧還是堆?

解除引用是否意味着'讀取指針地址處的值'?我認爲我的混淆是,我認爲它會失去對某些數據的引用;

int *x; 
x = new int; 
*x = 5; 
x = new int; // Dereferencing the first bit of memory allocated. 

感謝您的耐心,我希望這有一定道理的問題,

GAV株系

+0

對指針可能發生的所有問題的良好總結。 – 2010-02-08 11:58:47

+0

另一方面,變量名稱使其不可能遵循邏輯。真正的代碼永遠不會接近這個複雜的(或者說,不應該是) – 2013-01-30 19:24:19

回答

6

簡單地說:一個指針,其值,你可能有興趣在一個變量的地址

間接引用是訪問該值的行爲 - 在前面加上了*(對其操作)的。指針變量。訪問可以用於閱讀,寫作或兩者兼而有之。

  1. 如果您沒有初始化指向有效地址(或特殊值NULL)的指針 - 您不知道該變量包含的是什麼。解引用將嘗試將所有內容都視爲地址。這是未定義的行爲 - 所有投注都關閉,任何事情都可能發生,但如果幸運的話,最終會出現陷阱/硬件異常。

  2. 沒錯。因爲,p正在保存您分配的某個內存的地址。不釋放系統資源會導致泄漏。解引用已刪除的指針與解引用未初始化的指針相同 - 您不知道它可能包含的值。

  3. 同樣,UB。

  4. 是的。你的UB爲x == 0。晃來晃去的指針是危險的,因爲它們在最不合時宜的時候爬起來,格式化你的硬盤並且再也看不到。不可能合理地證明你的程序將如何表現。

+0

+1。搖晃的指針也指向記憶,你將永遠不能再次到達。 – ALOToverflow 2010-02-08 12:42:10

+0

您點擊的關鍵點是第二句 - 我不知道術語解引用意味着訪問存儲在變量地址中的值。 我認爲這意味着像'無關緊要' - 刪除最後一個內存引用而不刪除它。 謝謝 – gav 2010-02-08 14:15:56

1

迴應你的需要:

  1. x的值從讀流。這可能會失敗,使x未初始化(存儲垃圾值)。所以if的行爲是不可靠的,因此它可能不會將地址分配給q。因此,分配*q = 3將寫入隨機存儲器地址。

  2. 這不好!沒有垃圾收集。第一個對象分配在堆上,它的地址分配給了p。現在您分配第二個指針並覆蓋指針以保存新地址。舊地址丟失了,所以沒有人可以通過p刪除它。後面有一個delete q,它是p的地址的副本,但該聲明取決於x(這是不可靠的)的值。

  3. 這不是指針已被刪除。這是指向的對象。該指針仍然保存着一個指向曾經是有效對象的值,但現在是垃圾。如果你解除引用,你的程序將會有「未定義的行爲」。

  4. 是的。運行時系統(比如它)沒有跟蹤指向對象的指針。

2

在:

  1. 可以通過從地址解引用它來具體內存see Pointer dereference doc.分配q指針。但是由於if條件將其設置爲地址x它可以指向隨機存儲單元(未初始化),如果x <= 0
  2. 在上面的行中,您將q設置爲指向與p相同的內存地址。然後爲p分配新的內存。然後你分配p指向的新內存。
  3. 上面的行刪除了q指向的內存分配。此內存地址現在可供系統使用。在此之後,您爲內存賦值並不屬於您。
  4. 如果x == 0則返回到qp指向的系統內存。並再次嘗試使用不屬於你的內存。如果x != 0也沒有delete p - 因此內存不會返回到系統。
3

增加了更多的評論中,線下:

int x, *p, *q; 
    p = new int; 
    cin >> x; 
    if (x > 0) q = &x; 
    *q = 3;     // <--- 1. deref of possibly uninitialized ptr q 
          // 
          // q has never been set or is set to point at a non 
          // allocated memory location (if x > 0) 
          // 
          // If x is zero q is uninitialized (has random value). 
          // Therefore de-referencing it to set what it points at 
          // to 3 has undefined behavior. 

    q = p; 
    p = new int;   // <--- 2. potential storage leak (if x != 0 this 
          //  memory will not be returned to free storage) 
          // 
          // This comment is not true. The value pointed at by p 
          // was transferred to q before p was re-assigned. Thus 
          // there is no potential memory leak. Both p and q are 
          // now valid pointers. 
    *p = 5; 
    delete q; 
    *q = 1;     // <--- 3. deref of deleted ptr q 
          // 
          // In the line above you returned the memory pointed at 
          // by q back to memory management routines (via delete). 
          // Technically q still points at the memory but you no 
          // longer own that memory and thus writing to it has 
          // undefined behavior (because the memory management 
          // system could have unloaded that chunk from virtual 
          // memory or re-used it some other way). 
    q = p; 
    if (x == 0) delete q; 
    (*p)++;     // <--- 4. deref of possibly dangling ptr p (if x is zero) 
          // 
          // q is reassinged to have the same pointer value as p. 
          // Then If x is zero we delete the pointer q (thus 
          // returning it to the memory management pool). Since p 
          // and q are the same pointer they both become invalid at 
          // point. Thus de-referencing p is undefined behavior if 
          // x is zero (because the memory was returned (via delete) 

1我們要麼分配X(& *當然Q)在3或當q = & X那麼q有!因爲它是未初始化的,我們剛剛分配了一個隨機片段的內存值3.我不確定如何解引用未初始化的內容?

見下文:

3這有什麼錯解引用刪除指針?在'刪除q'之後* q是無意義的?

內存屬於別人(內存管理(或線程化應用可能已經被重新分配給其他線程)。寫入內存不屬於你了不確定的行爲。

4有什麼問題懸擺指針嗎?現在是內存可行的重新分配,我們已經刪除了它,即使我們仍然有一個指向它?

相同的註釋爲3(只是因爲你保留了無效的指針呢不代表什麼)

解除引用的意思是'讀取指針地址的值'?我認爲我的混淆是,我認爲它會失去對某些數據的引用;

是的:這就是全部意思。
但是,如果你不擁有這種記憶可能會發生令人討厭的事情。

  • 如果指針指向內存中未映射到物理內存的位置,則會出現某種形式的分段錯誤。
  • 如果內存屬於內存管理例程,並且開始將隨機值(如上面的3)寫入內存管理例程,則可能會損壞內存管理結構,從而導致程序在任何內存管理髮生時崩潰。
  • 如果內存屬於堆棧並開始寫入隨機值(如上面的3),則可能會覆蓋另一個隨機變量或函數退出時使用的返回地址。
2

如果您不知道「引擎蓋下」發生了什麼,這是一個很難的課題。 C++是一種'裸機'編程語言,很少使任何安全。

看着你提供的代碼和感興趣的標記點:

第一行有:int x, *p, *q;它聲明並定義在堆棧上一些變數,但不會初始化它們。在運行時,C++也不記得發生了這種情況。編譯時你可能會得到一些警告,但除此之外,你必須跟蹤你腦海中的事情。

因此,在行1.我們不知道q是否是&x或不。如果q沒有被初始化,那麼它可能指向任何地方,但是C++不知道,並且會嘗試將值3寫入某處的某個內存。這一點的答案是C++不跟蹤指針值。

在第3.行,C++正在嘗試向某段內存寫入一個整數值,但這次它在堆上和多線程程序中可能已在此行執行時重新分配。所以,不幸的是q*q保留的含義,但它不可能意味着我們想要的。

在行4.其與3.相同的問題,但只有在(x==0),如你所說,是的,即使我們已經刪除它,內存可能已被重新分配。

聲明一個int指針只爲指針分配內存單獨和在堆棧上。

解引用指針意味着訪問指針所指向的內存,用於讀取或寫入。

關於您的第二片的代碼:用於讀取或寫入到存儲器,該指針指向

int *x;   <-- Declares a pointer and allocates it on the stack 
x = new int; <-- Allocate a new int on the heap and remember its address in x 
*x = 5;   <-- Overwrite the new int on the heap. 
x = new int; <-- Another allocation and remember its address in x 
        Now we have forgotten where the first allocation was 

解除引用。如果你只是讀或寫指針本身,那麼它總是安全的。這就是爲什麼你可以傳遞一個指針,只有在第一次解除引用時纔會遇到麻煩。