簡體   English   中英

C ++返回指針/引用

[英]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;
}
  1. returnA()我要求返回一個指針; 只是為了澄清這是有效的,因為j是一個指針?
  2. returnB()我要求返回一個指針; 因為指針指向一個地址, returnB()工作的原因是因為我正在返回&b
  3. returnC()我要求返回一個int的地址。 當我返回c&運算符會自動“追加” c
  4. returnC2()我再次詢問要返回的int的地址。 *d是否有效,因為指針指向一個地址?

假設a,b,c被初始化為整數為Global。

有人可以驗證我的所有四個問題是否正確?

雖然彼得回答了你的問題,但有一點讓你感到困惑的是符號*& 有關獲取你的頭圍繞這些最困難的部分是,它們都具有與間接做兩個不同的含義(即使剔除的第三含義*乘法和&按位和)。

  • * ,當用作類型的一部分時,表示類型是指針: int是一個類型,因此int*是指向int的類型,而int**是指向指針到int類型的指針。

  • &當用作類型的一部分時表示該類型是引用。 int是一個類型,所以int&是一個引用到int(沒有引用引用這樣的東西)。 引用和指針用於類似的事情,但它們是完全不同的,不可互換。 最好將引用視為現有變量的別名或備用名稱。 如果xint ,那么您可以簡單地指定int& y = x來為x創建新名稱y 后, xy可以互換使用,以指代相同的整數。 這樣做的兩個主要含義是引用不能為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM