在這里,我在 1 個 cpp 檔案中有一些 c 代碼:
struct Object
{
int* data;
}
Object obj;
void pizza()
{
int joe[] = {5, 3, 4, 7, 8};
obj.data = joe;
}
int main()
{
pizza();
std::cout << obj.data[2];
return 0;
}
obj.data 只是一個指向整數陣列的指標,我在 Pizza 函式中對其進行了初始化,所以當它離開這個函式時,obj.data 應該指向 NULL,因為這些資料只存在于 Pizza 的范圍內。
但事實并非如此,當我 std::cout 這個陣列的值時,即使指標指向不再有效的資料,資料仍然存在。
這是如何作業的,是否正在復制資料?這是安全的還是會導致問題?
uj5u.com熱心網友回復:
在這個函式中:
void pizza()
{
int joe[] = {5, 3, 4, 7, 8};
obj.data = joe;
}
joe 僅在該函式運行時存在;它在堆疊上分配。披薩吃完后,該記憶體會自動釋放,但您已將 joe 的地址保存在 obj.data 中。這意味著 obj.data 現在指向無效記憶體。
它“有效”的原因是因為您“幸運”;讀取該指標無效,觸發所謂的“未定義行為”,即 UB。在某些情況下(最難除錯),一切似乎都可以正常作業,但稍后當您更改某些內容(或客戶下了意外的大訂單)時,它就會失敗。
在您的情況下,請嘗試重復 std::cout,它可能會給您不同的答案。
我將回應 Ted Lyngmo 在另一個答案中所說的話(并添加我自己的)
- 不要使用原始指標,使用 std::shared_ptr 或 std::unique_ptr
- 不要使用原始陣列,使用 std::vector
uj5u.com熱心網友回復:
C 指標的作用域是什么?
指標與任何其他變數具有相同的范圍。它通常是區域變數,有時是全域變數。
{
auto im_a_pointer = function_that_returns_a_pointer();
} // `im_a_pointer` goes out of scope and can't be used anymore
問題通常不是指標本身。懸空指標是雖然。取消參考指向已結束其生命的物件的指標會使您的程式具有未定義的行為。
void pizza()
{
int joe[] = {5, 3, 4, 7, 8};
obj.data = joe;
} // `joe`s life ends here - try to access it and you'll have undefined behavior
由于指標指向(可能)活動的物件,因此傳遞指標不會引起問題。您可以按值回傳指標。它復制指標并且對它實際指向的物件的生命周期沒有任何影響。
關于那個話題——不從任何函式回傳原始的擁有指標是保持理智的一種方法。std::unique_ptr<type>如果所有權是混合的,請使用。
uj5u.com熱心網友回復:
陣列 joe 的值在運行時放置在堆疊資料結構中。該堆疊在退出時被拆除pizza()。作為一種優化,拆除意味著重置堆疊頂部位置:回收堆疊空間中的實際值不需要更改,實際上您的編譯器已選擇不重置回收堆疊中的值。
函式pizza()退出時,obj.data不修改 的值,即保留該值。并且在列印值時看到回收堆疊中的值沒有被修改,它仍然會輸出 value 4。它是值的事實4純屬偶然,因為該記憶體位置可能已被重用。為了說明這一點,以下代碼很有可能不再列印4,因為該方法很pie()可能會覆寫先前回收的堆疊空間。
#include <iostream>
using namespace std;
struct Object
{
int* data;
};
struct Object obj;
void pizza()
{
int joe[] = {5, 3, 4, 7, 8};
obj.data = joe;
}
void pie()
{
int bob[] = {10, 11, 12, 13, 14};
}
int main()
{
pizza();
pie();
std::cout << obj.data[2];
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/430727.html
上一篇:c 中帶有陣列的指標的奇怪行為
