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;
}
- W
returnA()
proszę o zwrócenie wskaźnika; tylko dla wyjaśnienia to działa, ponieważj
czy wskaźnik? - W
returnB()
proszę o zwrócenie wskaźnika; ponieważ wskaźnik wskazuje na adres, powodem działaniareturnB()
jest to, że zwracam&b
? - W
returnC()
pytam aby adresint
został zwrócony. Kiedy zwracamc
czy operator&
jest automatycznie "dołączany"c
? - W
returnC2()
ponownie proszę o zwrot adresuint
. 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?
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
.
Tak. Tutaj dzieje się to samo, co powyżej, tylko w jednym kroku.W returnb() proszę o zwrócenie wskaźnika; ponieważ wskaźnik wskazuje na adres, powodem działania returnB() jest to, że zwracam &b?
&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.
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ęcint*
jest pointer-to-int typ iint**
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ślix
jestint
, to można po prostu Przypiszint& y = x
, aby utworzyć nową nazwęy
dlax
. Po wyrazach,x
iy
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ślip
jest wskaźnikiem do int, {[20] } jest wskazywany naint
.&
w przypadku użycia jako operator jednoargumentowy wykonuje operację o nazwie address-of. To dość oczywiste; jeślix
jest zmienna, wtedy&x
jest adresemx
. Adres zmiennej może być przypisany do wskaźnika typu tej zmiennej. Jeśli więcx
jestint
, to&x
może być przypisany do wskaźnika typuint*
, A wskaźnik ten będzie wskazywał nax
. Np. jeśli przypisujeszint* p = &x
, to*p
może być użyte do pobrania wartościx
.
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.
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
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.
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.
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.
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