我是 C 和 C 的新手。我知道,每當呼叫一個函式時,它的變數都會在堆疊上分配記憶體,這包括變數恰好是指向通過malloc或在堆上分配的資料的指標的情況new(但我聽說不能保證malloc 分配的存盤在堆上是 100%,如果我錯了,請糾正我)。例如,
Void fn(){
Member *p = new Member()
}
或者
Void fn() {
int *p = (int*) malloc( sizeof(int) * 10 );
}
如果我錯了,請更正,在這兩種情況下,變數p(保存堆上分配的物件的地址)都在堆疊上,它指向堆上的物件。那么說我們宣告的所有變數都在堆疊上是否正確,即使它們可能指向堆上的某些東西?假設區域變數指標的地址p被加載到記憶體地址001,它具有位于堆上的成員物件的地址,該地址是002。我們可以畫出這樣的圖。

如果這是正確的,我的下一個問題是,我們是否可以有一個實際位于堆上的指標,它指向位于堆疊上的變數?如果不可能,該指標是否可以指向位于堆上的變數?也許用另一種方式來表達這個問題是:為了訪問堆中的東西,我們只能通過堆疊上的指標來訪問它? 可能的圖表可能如下所示
如果可能的話,我可以在這里舉個例子嗎?

uj5u.com熱心網友回復:
是的,您可以將指標放在空閑存盤(堆)上并讓它指向堆疊上的變數。訣竅是創建一個指向指標(int**)的指標:
int main()
{
int i = 0; // int on the stack
int** ip = new int*; // create an int* (int pointer) on the free store (heap)
// ip (the int**) is still on the stack
*ip = &i;
// Now your free store (heap) located pointer points
// to your stack based variable i
delete ip; // clean up
}
注意:術語“堆”和“堆疊”是通用的、易于理解的計算術語。在 C 中,它們在標準中被稱為“自由存盤”,并且(盡管沒有直接命名)“堆疊”是 100% 隱含的(例如,通過對“堆疊展開”的參考),因此是必需的。
uj5u.com熱心網友回復:
堆疊和堆沒有被標準專門定義。這些是實作細節。
堆是指許多作業系統用來幫助它們安全地管理為同時運行的不同程式分配的空間的一種資料結構。
請記住,這并不是作業系統所使用的。事實上,作業系統使用一種更高級的堆資料結構形式,允許它們執行多種復雜的與記憶體相關的任務。此外,并非每個作業系統都使用堆資料結構實作免費存盤。有些人可能會使用不同的技術。
而堆疊要簡單得多:

我們可以有一個實際位于堆上的指標,它指向位于堆疊上的變數嗎?
是的,這是可能的,但很少需要:
#include <iostream>
int main( )
{
int a_variable_on_stack { 5 };
int** ptr_on_stack { new int*( &a_variable_on_stack ) };
std::cout << "address of `a_variable_on_stack`: " << &a_variable_on_stack << '\n'
<< "address of ptr on the heap: " << ptr_on_stack << '\n'
<< "value of ptr on the heap: " << *ptr_on_stack << '\n';
std::cin.get( );
}
可能的輸出:
address of `a_variable_on_stack`: 0x47eb5ffd2c
address of ptr on the heap: 0x1de33cc3810
value of ptr on the heap: 0x47eb5ffd2c
注意a_variable_on_stackptr 存盤在堆上的地址和值都是0x47eb5ffd2c。換句話說,堆上的指標持有堆疊上變數的地址。
uj5u.com熱心網友回復:
簡而言之:
在函式中宣告的變數在堆疊上分配,并且可以指向任何你想要的(堆疊上其他變數的地址和堆上其他變數的地址)。
對于在堆上宣告的變數也是如此。它們可以指向堆上其他變數的地址或堆疊上變數的地址。這里沒有限制。
但是,在堆疊上宣告的變數本質上是臨時的,并且當函式回傳時,該記憶體被回收。因此,在堆疊中擁有指向變數地址的指標不是一個好習慣,除非您知道函式尚未完成(即使用同一函式內的區域變數地址或同一函式內的函式呼叫)。新手 C/C 開發人員的一個常見錯誤是從函式回傳堆疊上宣告的變數地址。當函式回傳時,這塊記憶體被回收,很快就會被其他函式呼叫的記憶體重用,所以訪問這個地址有未定義的行為。
uj5u.com熱心網友回復:
我是 C 和 C 的新手。
您的問題不是 C 或 C 特定的,而是一般的編程語言。
...每當呼叫一個函式時,它的變數都會在堆疊上分配記憶體...
這是正確的:幾乎所有的編譯器都是這樣做的。
但是,也有例外 - 例如在 SPARC 或 TriCore CPU 上,它們具有特殊功能......
malloc...通過...分配在堆上
malloc 從不在堆疊上分配記憶體,而是在堆上。
... 不能保證 malloc 分配的存盤在堆上是 100% ...
與“堆疊”一詞不同,“堆”一詞的含義因情況而異。
在某些情況下,“堆”一詞用于指定由mallocand使用的特定記憶體區域new。
如果該記憶體區域中沒有足夠的記憶體,malloc(或new)向作業系統請求不同記憶體區域中的記憶體。
但是,其他人也會將該記憶體區域稱為“堆”。
...在這兩種情況下,變數
p都在堆疊上,它指向堆上的物件。
這是對的。
...我們可以有一個實際位于堆上的指標,它指向位于堆疊上的變數嗎?
當然:
int ** allocatedMemory;
void myFunction()
{
int variableOnStack;
allocatedMemory = (int **)malloc(sizeof(int *));
*allocatedMemory = &variableOnStack;
...
}
該變數allocatedMemory指向堆上的一些資料,而該資料是指向variableOnStack堆疊上變數 () 的指標。
但是,當函式myFunction()回傳時,變數variableOnStack不再存在。假設該函式在以下otherFunction()時間呼叫myFunction():
void otherFunction()
{
int a;
int b;
...
}
現在我們不知道 if*allocatedMemory指向a、 tob甚至是“回傳地址”,因為我們不知道這兩個變數中的哪一個與variableOnStack.
如果我們現在寫信,可能會發生壞事**allocatedMemory……
為了訪問堆中的東西,我們只能通過堆疊上的指標來訪問它??
... 圖“B” ...
要訪問堆上的某些資料,您肯定需要一些未存盤在堆上的指標。
該指標可以是:
- 全域變數或
static變數
在我上面的示例中,allocatedMemory是一個全域變數。
全域和static變數既不存盤在完全不同的記憶體區域(不是堆也不是堆疊) - 堆疊上的區域變數
- CPU 暫存器中的區域變數
(我已經寫過區域變數并不總是存盤在堆疊中)
理論上,圖“B”中的情況是可能的:只需allocatedMemory用NULL(或另一個指標)覆寫變數。
但是,程式不能直接訪問堆上的資料。
這意味著p*如果沒有更多指標“在”指向p*.
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/412642.html
標籤:
