[英]C++ Returning Pointers/References
我對解除引用操作符,操作符的地址和指針有一個相當好的理解。
但是當我看到這樣的東西時,我感到很困惑:
int* returnA() {
int *j = &a;
return j;
}
int* returnB() {
return &b;
}
int& returnC() {
return c;
}
int& returnC2() {
int *d = &c;
return *d;
}
returnA()
我要求返回一個指針; 只是為了澄清這是有效的,因為j
是一個指針? returnB()
我要求返回一個指針; 因為指針指向一個地址, returnB()
工作的原因是因為我正在返回&b
? returnC()
我要求返回一個int
的地址。 當我返回c
, &
運算符會自動“追加” c
? returnC2()
我再次詢問要返回的int
的地址。 *d
是否有效,因為指針指向一個地址? 假設a,b,c被初始化為整數為Global。
有人可以驗證我的所有四個問題是否正確?
雖然彼得回答了你的問題,但有一點讓你感到困惑的是符號*
和&
。 有關獲取你的頭圍繞這些最困難的部分是,它們都具有與間接做兩個不同的含義(即使剔除的第三含義*
乘法和&
按位和)。
*
,當用作類型的一部分時,表示類型是指針: int
是一個類型,因此int*
是指向int的類型,而int**
是指向指針到int類型的指針。
&
當用作類型的一部分時表示該類型是引用。 int
是一個類型,所以int&
是一個引用到int(沒有引用引用這樣的東西)。 引用和指針用於類似的事情,但它們是完全不同的,不可互換。 最好將引用視為現有變量的別名或備用名稱。 如果x
是int
,那么您可以簡單地指定int& y = x
來為x
創建新名稱y
。 后, x
和y
可以互換使用,以指代相同的整數。 這樣做的兩個主要含義是引用不能為NULL(因為必須有一個原始變量來引用),並且您不需要使用任何特殊運算符來獲取原始值(因為它只是一個替代名稱,不是指針)。 引用也不能重新分配。
*
當用作一元運算符時,執行稱為解除引用的操作(與引用類型無關!)。 此操作僅對指針有意義。 當您取消引用指針時,您將返回它指向的內容。 因此,如果p
是指向int的指針,則*p
是指向的int
。
&
用作一元運算符執行稱為地址的操作時。 這是非常不言自明的; 如果x
是一個變量,那么&x
是的地址x
。 可以將變量的地址分配給指向該變量類型的指針。 因此,如果x
是一個int
,則可以將&x
分配給int*
類型的指針,該指針將指向x
。 例如,如果指定int* p = &x
,則可以使用*p
來檢索x
的值。
所以請記住,類型后綴&
是引用,並沒有任何與一元手術室&
,這與獲得的地址,以指針的使用做。 這兩種用途完全不相關。 *
作為類型后綴聲明指針,而*
作為一元運算符執行指針操作。
在returnA()中我要求返回一個指針; 只是為了澄清這是有效的,因為j是一個指針?
是的, int *j = &a
初始化j
指向a
。 然后返回j
的值,即a
的地址。
在returnB()中我要求返回一個指針; 因為指針指向一個地址,returnB()工作的原因是因為我正在返回&b?
是。 在這里,同樣的事情發生在上面,只需一步。 &b
給出的地址b
。
在returnC()中,我要求返回一個int的地址。 當我返回c時,&運算符會自動附加嗎?
不,它是對返回的int的引用。 引用不是與指針相同的地址 - 它只是變量的替代名稱。 因此,您無需應用&
運算符來獲取變量的引用。
在returnC2()中,我再次詢問要返回的int的地址。 * d是否有效,因為指針指向一個地址?
同樣,它是對返回的int的引用。 *d
指的是原始變量c
(無論可能是什么),由c
指出。 這可以隱含地變成一個引用,就像在returnC
。
指針通常不指向一個地址(盡管它們可以 - 例如int**
是指向int**
的指針)。 指針是某種東西的地址。 當您將指針聲明為something*
,指針指向的something
就是這樣。 所以在上面的例子中, int**
聲明了一個指向int*
的指針,它恰好是一個指針本身。
Tyler,這是非常有用的解釋,我做了一些使用visual studio調試器的實驗來進一步澄清這種差異: -
int sample = 90;
int& alias = sample;
int* pointerToSample = &sample;
Name Address Type
&alias 0x0112fc1c {90} int *
&sample 0x0112fc1c {90} int *
pointerToSample 0x0112fc1c {90} int *
*pointerToSample 90 int
alias 90 int &
&pointerToSample 0x0112fc04 {0x0112fc1c {90}} int * *
PointerToSample Sample/alias
_______________......____________________
0x0112fc1c | | 90 |
___________|___.....__|________|_______...
[0x0112fc04] ... [0x0112fc1c
在returnC()和returnC2()中,您不是要求返回地址。
這兩個函數都返回對象的引用。
引用不是任何東西的地址,它是某種東西的替代名稱(這可能意味着編譯器可能(或可能不依賴於情況)使用地址來表示對象(或者它也可能知道將其保留在寄存器中)) 。
所有你知道一個參考點指向一個特定的對象。
雖然引用本身不是對象,但只是一個替代名稱。
您的所有示例都會產生未定義的運行時行為。 您正在返回指針或對在執行離開函數后消失的項的引用。
讓我澄清一下:
int * returnA()
{
static int a; // The static keyword keeps the variable from disappearing.
int * j = 0; // Declare a pointer to an int and initialize to location 0.
j = &a; // j now points to a.
return j; // return the location of the static variable (evil).
}
在你的函數,變量j
分配給指向a
的臨時位置。 退出函數后,變量a
消失,但它的前一個位置是通過j
返回的。 因為a
不再存在於位置的指向j
,不確定的行為將與訪問發生*j
。
函數內部的變量不應通過引用或指針修改其他代碼。 它可能會發生,雖然它會產生未定義的行為。
作為迂腐,返回的指針應聲明為指向常量數據。 返回的引用應該是const:
const char * Hello()
{
static const char text[] = "Hello";
return text;
}
上面的函數返回一個指向常量數據的指針。 其他代碼可以訪問(讀取)靜態數據但不能修改。
const unsigned int& Counter()
{
static unsigned int value = 0;
value = value + 1;
return value;
}
在上面的函數中, value
在第一個條目上初始化為零。 此函數的所有下一次執行都會使value
增加1。 該函數返回對常量值的引用。 這意味着其他函數可以使用該值(來自遠方),就好像它是一個變量(無需取消引用指針)。
在我看來,指針用於可選參數或對象。 當對象必須存在時傳遞引用。 在函數內部,引用的參數意味着該值存在,但是在解除引用之前必須檢查指針是否為null。 此外,通過引用,可以更加保證目標對象有效。 指針可能指向無效的地址(非null)並導致未定義的行為。
從語義上講,引用確實充當地址。 但是,從語法上講,它們是編譯器的工作,而不是你的工作,並且你可以將引用視為它指向的原始對象,包括綁定對它的其他引用並讓它們引用原始對象。 在這種情況下告別指針算術。
這樣做的缺點是你無法修改它們所指的內容 - 它們在構造時受到約束。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.