C++ Zwracające Wskaźniki / Referencje

Mam dość dobre zrozumienie operatora dereferencyjnego, adresu operatora i wskaźników w ogóle.

Jednak się mylę, gdy widzę takie rzeczy:

int* returnA() {
    int *j = &a;
    return j;
}

int* returnB() {
    return &b;
}

int& returnC() {
    return c;
}

int& returnC2() {
    int *d = &c;
    return *d;
}
  1. W returnA() proszę o zwrócenie wskaźnika; tylko dla wyjaśnienia to działa, ponieważ j czy wskaźnik?
  2. W returnB() proszę o zwrócenie wskaźnika; ponieważ wskaźnik wskazuje na adres, powodem działania returnB() jest to, że zwracam &b?
  3. W returnC() pytam aby adres int został zwrócony. Kiedy zwracam c czy operator & jest automatycznie "dołączany" c?
  4. W returnC2() ponownie proszę o zwrot adresu int. Czy *d działa, ponieważ wskaźniki wskazują adres?

Załóżmy, że a, b, c są inicjalizowane jako liczby całkowite jako globalne.

Czy ktoś może potwierdzić, czy mam rację ze wszystkimi czterema pytaniami?

Author: Mustafa Ekici, 2010-05-15

6 answers

W return () proszę o zwrócenie wskaźnika; tylko dla wyjaśnienia to działa, ponieważ j jest wskaźnikiem?

Tak, int *j = &a inicjalizuje j, aby wskazać a. Następnie zwracamy wartość j, czyli adres a.

W returnb() proszę o zwrócenie wskaźnika; ponieważ wskaźnik wskazuje na adres, powodem działania returnB() jest to, że zwracam &b?

Tak. Tutaj dzieje się to samo, co powyżej, tylko w jednym kroku. &b podaje adres b.

W returnC() proszę o zwrócenie adresu int. Kiedy zwracam c czy operator & jest automatycznie dołączany?

Nie, jest to odniesienie do int, które jest zwracane. Odniesienie nie jest adresem tak samo jak wskaźnik-jest tylko alternatywną nazwą dla zmiennej. Dlatego nie trzeba stosować operatora &, aby uzyskać odniesienie do zmiennej.

In returnC2() I ' m asking again for adres Int do zwrotu. Czy *d działa, ponieważ wskaźniki wskazują adres?

Ponownie, jest to odniesienie do int, które jest zwracane. *d odnosi się do pierwotnej zmiennej c (cokolwiek to może być), wskazywanej przez c. I to może być w domyśle zamienione w odniesienie, tak jak w returnC.

Wskaźniki generalnie nie wskazują adresu (choć mogą - np. int** jest wskaźnikiem do wskaźnika do int). Pointers to adres czegoś. Kiedy deklarujesz wskaźnik jako something*, to {[14] } jest rzeczą, na którą wskazuje Twój wskaźnik. Tak więc w moim powyższym przykładzie int** deklaruje wskaźnik na int*, co zdarza się być wskaźnikiem.

 22
Author: Péter Török,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-14 20:22:09

Chociaż Piotr odpowiedział na twoje pytanie, jedną rzeczą, która wyraźnie Cię myli, są symbole * i &. Najtrudniejsze jest to, że obie mają dwa różne znaczenia, które mają związek z indirection (nawet z wyłączeniem trzeciego znaczenia {[0] } dla mnożenia i & dla bitowego-and).

  • *, W przypadku stosowania jako część typu wskazuje, że typ jest wskaźnikiem: int jest typem, więc int* jest pointer-to-int typ i int** jest Typ pointer-to-pointer-to-int.

  • & w przypadku użycia jako część typu wskazuje, że typ jest odniesieniem. int jest typem, więc {[10] } jest odniesieniem do int (nie ma czegoś takiego jak odniesienie do odniesienia). Odniesienia i wskaźniki są używane do podobnych rzeczy, ale są zupełnie inne i nie można ich wymieniać. Odniesienie najlepiej traktować jako alias lub alternatywną nazwę dla istniejącej zmiennej. Jeśli x jest int, to można po prostu Przypisz int& y = x, aby utworzyć nową nazwę y dla x. Po wyrazach, x i y mogą być używane zamiennie, aby odnosić się do tej samej liczby całkowitej. Dwie główne implikacje tego są takie, że odwołania nie mogą być NULL (ponieważ musi istnieć oryginalna zmienna do odwołania) i że nie trzeba używać żadnego specjalnego operatora, aby uzyskać oryginalną wartość(ponieważ jest to tylko alternatywna nazwa, a nie wskaźnik). Nie można również przypisać odniesień.

  • * W przypadku stosowania jako operator unary wykonuje operację o nazwie dereference (która nie ma nic wspólnego z typami referencji !). Ta operacja ma znaczenie tylko dla wskaźników. Kiedy odbierzesz wskaźnik, odzyskasz to, na co wskazuje. Tak więc, jeśli p jest wskaźnikiem do int, {[20] } jest wskazywany na int.

  • & w przypadku użycia jako operator jednoargumentowy wykonuje operację o nazwie address-of. To dość oczywiste; jeśli x jest zmienna, wtedy &x jest adresem x. Adres zmiennej może być przypisany do wskaźnika typu tej zmiennej. Jeśli więc x jest int, to &x może być przypisany do wskaźnika typu int*, A wskaźnik ten będzie wskazywał na x. Np. jeśli przypisujesz int* p = &x, to *p może być użyte do pobrania wartości x.

Więc pamiętaj, że przyrostek typu & służy do odniesień i nie ma nic wspólnego z jednoargumentowym operatorem &, który ma związek z uzyskiwanie adresów do użycia ze wskaźnikami. Te dwa zastosowania są całkowicie niepowiązane. I * jako przyrostek typu deklaruje wskaźnik, podczas gdy * jako operator jednoargumentowy wykonuje akcję na wskaźnikach.

 61
Author: Tyler McHenry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-15 13:56:44

Tyler, to było bardzo pomocne Wyjaśnienie, zrobiłem pewien eksperyment przy użyciu debuggera visual studio, aby wyjaśnić tę różnicę jeszcze bardziej: -

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 * *

Układ Pamięci

PointerToSample       Sample/alias
_______________......____________________
0x0112fc1c |          |   90   |
___________|___.....__|________|_______...

[0x0112fc04]  ...      [0x0112fc1c
 5
Author: Berhe Abrha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-16 03:44:25

W returnC () i returnC2() nie prosisz o zwrot adresu.

Obie te funkcje zwracają odwołania do obiektów.
Referencja nie jest adresem czegokolwiek, jest alternatywną nazwą czegoś (może to oznaczać, że kompilator może (lub nie może w zależności od sytuacji) użyć adresu do reprezentowania obiektu (alternatywnie może również wiedzieć, aby utrzymać go w rejestrze)).

Wszystko, co wiesz, że odniesienie wskazuje na konkretny obiekt.
Podczas gdy samo odniesienie nie jest obiekt tylko alternatywna nazwa.

 2
Author: Martin York,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-14 20:10:42

Wszystkie twoje przykłady wywołują nieokreślone zachowanie w czasie wykonywania. Zwracane są wskaźniki lub odniesienia do elementów, które znikają po zakończeniu wykonywania funkcji.

Pozwól mi wyjaśnić:

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).
}

W twojej funkcji zmienna {[3] } jest przypisana do miejsca tymczasowego a. Po zakończeniu funkcji zmienna a znika, ale jej poprzednia lokalizacja jest zwracana przez j. Ponieważ a nie istnieje już w miejscu wskazywanym przez j, undefined zachowanie będzie miało miejsce przy dostępie *j.

Zmienne wewnątrz funkcji nie powinny być modyfikowane za pomocą odniesienia lub wskaźnika za pomocą innego kodu. Może się zdarzyć, chociaż wywołuje nieokreślone zachowanie.

Jako pedantyczne, zwracane wskaźniki powinny być zadeklarowane jako wskazujące na stałe dane. Zwracane referencje powinny być const:

const char * Hello()
{
  static const char text[] = "Hello";
  return text;
}

Powyższa funkcja zwraca wskaźnik do stałych danych. Inny kod może uzyskać dostęp (odczyt) do danych statycznych, ale nie może być zmodyfikowany.

const unsigned int& Counter()
{
  static unsigned int value = 0;
  value = value + 1;
  return value;
}

W powyższej funkcji {[10] } jest inicjalizowana do zera przy pierwszym wpisie. Wszystkie następne wykonania tej funkcji powodują zwiększenie value o jeden. Funkcja zwraca odniesienie do stałej wartości. Oznacza to, że inne funkcje mogą używać wartości (z daleka) tak, jakby była zmienną (bez konieczności dereferencji wskaźnika).

W moim myśleniu wskaźnik jest używany do opcjonalnego parametru lub obiektu. Odniesienie jest przekazywane, gdy obiekt musi istnieć. Wewnątrz funkcji, parametr odniesienia oznacza, że wartość istnieje, jednak wskaźnik musi być sprawdzony pod kątem null przed dereferencją go. Ponadto, z odniesieniem, istnieje większa gwarancja, że obiekt docelowy jest ważny. Wskaźnik może wskazywać na nieprawidłowy adres (nie null) i powodować nieokreślone zachowanie.

 2
Author: Thomas Matthews,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-14 21:04:41

Semantycznie odniesienia działają jak adresy. Jednak składniowo, są one zadaniem kompilatora, a nie Twoim, i możesz traktować odniesienie tak, jakby było oryginalnym obiektem, do którego wskazuje, włączając w to powiązanie innych odniesień do niego i zmuszenie ich do odniesienia się do oryginalnego obiektu. W tym przypadku pożegnaj się z arytmetyką wskaźnika.

Minusem tego jest to, że nie można modyfikować tego, do czego się odnoszą - są związane w czasie konstruowania.

 1
Author: Puppy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-14 21:25:50