mało znany: operator jednoargumentowy plus może być użyty jako „operator rozpadu”: Biorąc pod uwagę int a[10]; int b(void);, +ajest on wskaźnikiem int i +bjest wskaźnikiem funkcji. Przydatne, jeśli chcesz przekazać go do szablonu akceptującego referencję.
Johannes Schaub - litb
3
@ litb - parens zrobiłby to samo (np. (a) powinno być wyrażeniem, którego wynikiem jest wskaźnik), prawda ?.
Michael Burr
21
std::decayz C ++ 14 byłby mniej niejasnym sposobem rozkładania tablicy na jednoargumentowy +.
legends2k
21
@ JohannesSchaub-litb, ponieważ pytanie to jest oznaczone zarówno C, jak i C ++, chciałbym wyjaśnić, że chociaż +ai +bsą legalne w C ++, to jest nielegalne w C (C11 6.5.3.3/1 „Operand unarny +lub -operator powinien mieć typ arytmetyczny ”)
MM
5
@lege Right. Ale przypuszczam, że nie jest to tak mało znane jak sztuczka z unary +. Powodem, dla którego wspomniałem, było nie tylko to, że rozkłada się, ale także dlatego, że jest to fajna zabawa;)
Johannes Schaub - litb
Odpowiedzi:
283
Mówi się, że tablice „rozpadają się” na wskaźniki. Tablicy C ++ zadeklarowanej jako int numbers [5]nie można ponownie wskazać, tzn. Nie można powiedzieć numbers = 0x5a5aff23. Co ważniejsze, termin zanik oznacza utratę rodzaju i wymiaru; numbersrozpadają się int*, tracąc informacje o wymiarach (liczba 5), a typ już nie int [5]istnieje. Poszukaj tutaj przypadków, w których rozpad się nie zdarza .
Jeśli przekazujesz tablicę według wartości, tak naprawdę to kopiujesz wskaźnik - wskaźnik do pierwszego elementu tablicy jest kopiowany do parametru (którego typ powinien być również wskaźnikiem typu elementu tablicy). Działa to z powodu rozkładającej się tablicy; po rozpadzie sizeofnie daje już pełnego rozmiaru tablicy, ponieważ zasadniczo staje się wskaźnikiem. Dlatego preferowane jest (między innymi) przekazywanie przez referencję lub wskaźnik.
Trzy sposoby przekazywania w tablicy 1 :
void by_value(const T* array)// const T array[] means the samevoid by_pointer(const T (*array)[U])void by_reference(const T (&array)[U])
Dwa ostatnie podadzą odpowiednie sizeofinformacje, a pierwszy nie, ponieważ argument tablicy zanikł, aby zostać przypisanym do parametru.
by_value przekazuje wskaźnik do pierwszego elementu tablicy; w kontekście parametrów funkcji T a[]jest identyczny z T *a. by_pointer przekazuje to samo, tyle że wartość wskaźnika jest teraz kwalifikowana const. Jeśli chcesz przekazać wskaźnik do tablicy (w przeciwieństwie do wskaźnika do pierwszego elementu tablicy), składnia jest następująca T (*array)[U].
John Bode
4
„z wyraźnym wskaźnikiem do tej tablicy” - jest to niepoprawne. Jeśli ajest tablicą char, to ajest typu char[N]i rozpadnie się na char*; ale &ajest rodzaju char(*)[N]i nie ulegnie rozkładowi.
Pavel Minaev,
5
@FredOverflow: Więc jeśli Uzmiany nie musisz pamiętać, aby zmienić go w dwóch miejscach lub zaryzykować ciche błędy ... Autonomia!
Wyścigi lekkości na orbicie
4
„Jeśli przekazujesz tablicę według wartości, tak naprawdę to kopiujesz wskaźnik” To nie ma sensu, ponieważ tablice nie mogą być przekazywane przez wartość, kropka.
juanchopanza
103
Tablice są w zasadzie takie same jak wskaźniki w C / C ++, ale nie do końca. Po przekonwertowaniu tablicy:
constint a[]={2,3,5,7,11};
do wskaźnika (który działa bez rzutowania, a zatem może się zdarzyć nieoczekiwanie w niektórych przypadkach):
constint* p = a;
tracisz zdolność sizeofoperatora do zliczania elementów w tablicy:
assert(sizeof(p)!=sizeof(a));// sizes are not equal
Tablice nie są zasadniczo takie same jak wskaźniki; to zupełnie inne zwierzęta. W większości kontekstów tablicę można traktować tak, jakby była wskaźnikiem, a wskaźnik można traktować tak, jakby była tablicą, ale jest tak blisko, jak to możliwe.
John Bode
20
@John, proszę wybaczyć mój nieprecyzyjny język. Próbowałem dotrzeć do odpowiedzi, nie zagłębiając się w długą historię, a „w zasadzie… ale nie całkiem” jest tak dobrym wytłumaczeniem, jak kiedykolwiek dostałem na studiach. Jestem pewien, że każdy zainteresowany może uzyskać dokładniejszy obraz z twojego pozytywnego komentarza.
system PAUZA
„działa bez rzutowania” oznacza to samo, co „dzieje się niejawnie”, gdy mówimy o konwersjach typu
MM
47
Oto, co mówi standard (C99 6.3.2.1/3 - Inne operandy - Wartości, tablice i desygnatory funkcji):
Z wyjątkiem sytuacji, gdy jest to operand operatora sizeof lub unary & operator lub dosłowny ciąg znaków używany do inicjalizacji tablicy, wyrażenie o typie „tablica typu” jest konwertowane na wyrażenie o wskaźniku typu „ wpisz '', który wskazuje początkowy element obiektu tablicy i nie jest wartością.
Oznacza to, że prawie za każdym razem, gdy nazwa tablicy jest używana w wyrażeniu, jest ona automatycznie konwertowana na wskaźnik do pierwszego elementu w tablicy.
Zauważ, że nazwy funkcji działają w podobny sposób, ale wskaźniki funkcji są używane znacznie rzadziej i w bardziej wyspecjalizowany sposób, że nie powoduje to prawie tyle zamieszania, co automatyczna konwersja nazw tablic na wskaźniki.
Standard C ++ (4.2 konwersja tablic na wskaźniki) rozluźnia wymaganie konwersji do (wyróżnienie moje):
Wartość lub wartość typu „tablica NT” lub „tablica nieznanych granic T” można przekonwertować na wartość typu „wskaźnik na T.”
Tak więc konwersja nie musi się odbywać tak, jak zawsze w C (pozwala to na przeciążenie funkcji lub dopasowanie szablonów do typu tablicy).
Dlatego też w C należy unikać używania parametrów tablic w prototypach / definicjach funkcji (moim zdaniem - nie jestem pewien, czy istnieje jakakolwiek ogólna zgoda). Powodują zamieszanie i są fikcją - użyj parametrów wskaźnika, a zamieszanie może nie zniknąć całkowicie, ale przynajmniej deklaracja parametru nie kłamie.
Jaki jest przykładowy wiersz kodu, w którym „wyrażenie mające typ„ tablica typu ”to„ literał łańcuchowy używany do inicjalizacji tablicy ”?
Garrett,
4
@Garrett char x[] = "Hello";. Szereg 6 elementów "Hello"nie ulega rozpadowi; zamiast tego xotrzymuje rozmiar, 6a jego elementy są inicjowane z elementów "Hello".
MM
30
„Rozpad” odnosi się do niejawnej konwersji wyrażenia z typu tablicowego na typ wskaźnika. W większości kontekstów, gdy kompilator widzi wyrażenie tablicowe, konwertuje typ wyrażenia z „tablicy N-elementowej T” na „wskaźnik do T” i ustawia wartość wyrażenia na adres pierwszego elementu tablicy . Wyjątki od tej reguły są przypadki, gdy tablica jest operand się z tych sizeoflub &operatorów, czy tablica jest ciągiem dosłowne używany jako inicjator w deklaracji.
Załóżmy następujący kod:
char a[80];
strcpy(a,"This is a test");
Wyrażenie ajest typu „80-elementowa tablica char”, a wyrażenie „This is a test” jest typu „16-elementowa tablica char” (w C; w C ++ literały łańcuchowe to tablice const char). Jednak w wywołaniu do strcpy()żadne wyrażenie nie jest operandem sizeoflub &, więc ich typy są domyślnie konwertowane na „wskaźnik na char”, a ich wartości są ustawiane na adres pierwszego elementu w każdym z nich. Co strcpy()otrzymuje nie są tablice, ale wskaźniki, co widać w jego prototypu:
char*strcpy(char*dest,constchar*src);
To nie to samo, co wskaźnik tablicowy. Na przykład:
Pamiętaj, że wyrażenie a[i]jest interpretowane jako *(a+i)(który działa tylko wtedy, gdy typ tablica jest przekształcany do typu wskaźnika), tak jak a[i]i ptr_to_first_element[i]działają tak samo. Wyrażenie (*ptr_to_array)[i]jest interpretowane jako *(*a+i). Wyrażenia *ptr_to_array[i]i ptr_to_array[i]mogą prowadzić do ostrzeżeń lub błędów kompilatora w zależności od kontekstu; na pewno zrobią coś złego, jeśli oczekujesz od nich oceny a[i].
sizeof a ==sizeof*ptr_to_array ==80
Ponownie, gdy tablica jest operandem sizeof, nie jest konwertowana na typ wskaźnika.
sizeof*ptr_to_first_element ==sizeof(char)==1sizeof ptr_to_first_element ==sizeof(char*)== whatever the pointer size
is on your platform
ptr_to_first_element jest prostym wskaźnikiem do char.
Nie jest ? (długość 14 + 1 dla \ 0)"This is a test" is of type "16-element array of char""15-element array of char"
chux - Przywróć Monikę
16
Tablice w C nie mają wartości.
Wszędzie tam, gdzie oczekiwana jest wartość obiektu, ale obiekt jest tablicą, używany jest adres jego pierwszego elementu z typem pointer to (type of array elements).
W funkcji wszystkie parametry są przekazywane przez wartość (tablice nie są wyjątkiem). Gdy przekazujesz tablicę w funkcji, „rozkłada się ona na wskaźnik” (sic); kiedy porównasz tablicę do czegoś innego, znowu „rozpada się ona na wskaźnik” (sic); ...
void foo(int arr[]);
Funkcja foo oczekuje wartości tablicy. Ale w C tablice nie mają żadnej wartości! Więc foodostaje zamiast adres pierwszego elementu tablicy.
int arr[5];int*ip =&(arr[1]);if(arr == ip){/* something; */}
W powyższym porównaniu arrnie ma wartości, więc staje się wskaźnikiem. Staje się wskaźnikiem do int. Ten wskaźnik można porównać ze zmienną ip.
W składni indeksowania tablic, do której jesteś przyzwyczajony, znowu arr jest „rozkładany na wskaźnik”
arr[42];/* same as *(arr + 42); *//* same as *(&(arr[0]) + 42); */
Tablica nie rozpada się na wskaźnik tylko wtedy, gdy jest operandem operatora sizeof, operatora & (adres operatora) lub literału łańcuchowego używanego do inicjalizacji tablicy znaków.
„Tablice nie mają wartości” - co to ma znaczyć? Oczywiście tablice mają wartość ... są obiektami, możesz mieć wskaźniki, a w C ++ odniesienia do nich itp.
Pavel Minaev
2
Uważam, że „Wartość” jest zdefiniowana w C jako interpretacja bitów obiektu według typu. Trudno mi znaleźć przydatne znaczenie tego typu tablic. Zamiast tego możesz powiedzieć, że konwertujesz na wskaźnik, ale to nie interpretuje zawartości tablicy, tylko pobiera jej lokalizację. Otrzymujesz wartość wskaźnika (i jest to adres), a nie wartość tablicy (byłaby to „sekwencja wartości zawartych elementów”, zgodnie z definicją „łańcucha”). To powiedziawszy, myślę, że uczciwie jest mówić „wartość tablicy”, kiedy oznacza się wskaźnik, który się otrzymuje.
Johannes Schaub - litb
w każdym razie wydaje mi się, że istnieje niewielka dwuznaczność: wartość obiektu i wartość wyrażenia (jak w „wartości”). Jeśli zostanie zinterpretowany w ten drugi sposób, to wyrażenie tablicowe z pewnością ma wartość: jest to wynik wynikające z rozkładu go na wartość i jest wyrażeniem wskaźnikowym. Ale jeśli zostanie zinterpretowany w ten sam sposób, to oczywiście nie ma użytecznego znaczenia dla obiektu tablicowego.
Johannes Schaub - litb
1
+1 dla frazy z niewielką poprawką; dla tablic nie jest to nawet triplet, tylko dwuwiersz [lokalizacja, typ]. Czy miałeś na myśli coś innego o trzeciej lokalizacji w przypadku tablicy? Nie mogę wymyślić żadnego.
legends2k
1
@ legends2k: Myślę, że użyłem trzeciej lokalizacji w tablicach, aby uniknąć uczynienia ich szczególnym przypadkiem posiadania tylko dwuwierszów. Może [lokalizacja, typ, nieważność ] byłoby lepsze.
pmg
8
To kiedy gnije tablica i jest wskazywana ;-)
Właściwie to po prostu to, że jeśli chcesz gdzieś przekazać tablicę, ale zamiast niej jest przekazywany wskaźnik (bo kto, do diabła, przekazałby ci całą tablicę), ludzie mówią, że słaba tablica uległa rozkładowi na wskaźnik.
Ładnie powiedziane. Co byłoby ładną tablicą, która nie rozpada się na wskaźnik lub taki, który nie ulega rozpadowi? Czy możesz podać przykład w C? Dzięki.
Unheilig,
@Uheheilig, oczywiście, można spakować próżniowo tablicę do struktury i przekazać strukturę.
Michael Krelin - haker
Nie jestem pewien, co rozumiesz przez „pracę”. Nie można uzyskać dostępu poza tablicą, ale działa zgodnie z oczekiwaniami, jeśli spodziewasz się, co naprawdę się stanie. To zachowanie (choć ponownie oficjalnie niezdefiniowane) zostaje zachowane.
Michael Krelin - haker
Rozpad występuje również w wielu sytuacjach, które nigdzie nie przekazują tablicy (jak opisano w innych odpowiedziach). Na przykład a + 1.
MM
3
Rozkład tablicy oznacza, że kiedy tablica jest przekazywana jako parametr do funkcji, jest traktowana identycznie jak wskaźnik („rozpada się”).
void do_something(int*array){// We don't know how big array is here, because it's decayed to a pointer.
printf("%i\n",sizeof(array));// always prints 4 on a 32-bit machine}int main (int argc,char**argv){int a[10];int b[20];int*c;
printf("%zu\n",sizeof(a));//prints 40 on a 32-bit machine
printf("%zu\n",sizeof(b));//prints 80 on a 32-bit machine
printf("%zu\n",sizeof(c));//prints 4 on a 32-bit machine
do_something(a);
do_something(b);
do_something(c);}
Istnieją dwa powikłania lub wyjątki od powyższego.
Po pierwsze, w przypadku tablic wielowymiarowych w C i C ++ tracony jest tylko pierwszy wymiar. Wynika to z faktu, że tablice są ułożone w pamięci w sposób ciągły, więc kompilator musi znać wszystkie oprócz pierwszego wymiaru, aby móc obliczyć przesunięcia w tym bloku pamięci.
void do_something(int array[][10]){// We don't know how big the first dimension is.}int main(int argc,char*argv[]){int a[5][10];int b[20][10];
do_something(a);
do_something(b);return0;}
Po drugie, w C ++ możesz użyć szablonów, aby wydedukować rozmiar tablic. Microsoft używa tego dla wersji C ++ funkcji Secure CRT, takich jak strcpy_s , i możesz użyć podobnej sztuczki, aby niezawodnie uzyskać liczbę elementów w tablicy .
Mogę śmiało myśleć, że istnieją cztery (4) sposoby przekazywania tablicy jako argumentu funkcji. Również tutaj jest krótki, ale działający kod dla twojego przeglądu.
#include<iostream>#include<string>#include<vector>#include<cassert>usingnamespace std;// test data// notice native array init with no copy aka "="// not possible in Cconstchar* specimen[]{ __TIME__, __DATE__, __TIMESTAMP__ };// ONE// simple, dangerous and uselesstemplate<typename T>void as_pointer(const T*array){// a pointer
assert(array!=nullptr);};// TWO// for above const T array[] means the same// but and also , minimum array size indication might be given too// this also does not stop the array decay into T *// thus size information is losttemplate<typename T>void by_value_no_size(const T array[0xFF]){// decayed to a pointer
assert(array!=nullptr);}// THREE// size information is preserved// but pointer is asked fortemplate<typename T,size_t N>void pointer_to_array(const T (*array)[N]){// dealing with native pointer
assert(array!=nullptr);}// FOUR// no C equivalent// array by reference// size is preservedtemplate<typename T,size_t N>void reference_to_array(const T (&array)[N]){// array is not a pointer here// it is (almost) a container// most of the std:: lib algorithms // do work on array reference, for example// range for requires std::begin() and std::end()// on the type passed as range to iterate overfor(auto&& elem :array){
cout << endl << elem ;}}int main(){// ONE
as_pointer(specimen);// TWO
by_value_no_size(specimen);// THREE
pointer_to_array(&specimen);// FOUR
reference_to_array( specimen );}
Mógłbym również sądzić, że pokazuje to wyższość C ++ w porównaniu z C. Przynajmniej w odniesieniu (w zamierzeniu pun) przekazywania tablicy przez referencję.
Oczywiście istnieją wyjątkowo surowe projekty bez alokacji sterty, bez wyjątków i bez std :: lib. Można powiedzieć, że natywna obsługa macierzy w C ++ to kluczowa funkcja języka.
int a[10]; int b(void);
,+a
jest on wskaźnikiem int i+b
jest wskaźnikiem funkcji. Przydatne, jeśli chcesz przekazać go do szablonu akceptującego referencję.std::decay
z C ++ 14 byłby mniej niejasnym sposobem rozkładania tablicy na jednoargumentowy +.+a
i+b
są legalne w C ++, to jest nielegalne w C (C11 6.5.3.3/1 „Operand unarny+
lub-
operator powinien mieć typ arytmetyczny ”)Odpowiedzi:
Mówi się, że tablice „rozpadają się” na wskaźniki. Tablicy C ++ zadeklarowanej jako
int numbers [5]
nie można ponownie wskazać, tzn. Nie można powiedziećnumbers = 0x5a5aff23
. Co ważniejsze, termin zanik oznacza utratę rodzaju i wymiaru;numbers
rozpadają sięint*
, tracąc informacje o wymiarach (liczba 5), a typ już nieint [5]
istnieje. Poszukaj tutaj przypadków, w których rozpad się nie zdarza .Jeśli przekazujesz tablicę według wartości, tak naprawdę to kopiujesz wskaźnik - wskaźnik do pierwszego elementu tablicy jest kopiowany do parametru (którego typ powinien być również wskaźnikiem typu elementu tablicy). Działa to z powodu rozkładającej się tablicy; po rozpadzie
sizeof
nie daje już pełnego rozmiaru tablicy, ponieważ zasadniczo staje się wskaźnikiem. Dlatego preferowane jest (między innymi) przekazywanie przez referencję lub wskaźnik.Trzy sposoby przekazywania w tablicy 1 :
Dwa ostatnie podadzą odpowiednie
sizeof
informacje, a pierwszy nie, ponieważ argument tablicy zanikł, aby zostać przypisanym do parametru.1 Stała U powinna być znana w czasie kompilacji.
źródło
T a[]
jest identyczny zT *a
. by_pointer przekazuje to samo, tyle że wartość wskaźnika jest teraz kwalifikowanaconst
. Jeśli chcesz przekazać wskaźnik do tablicy (w przeciwieństwie do wskaźnika do pierwszego elementu tablicy), składnia jest następującaT (*array)[U]
.a
jest tablicąchar
, toa
jest typuchar[N]
i rozpadnie się nachar*
; ale&a
jest rodzajuchar(*)[N]
i nie ulegnie rozkładowi.U
zmiany nie musisz pamiętać, aby zmienić go w dwóch miejscach lub zaryzykować ciche błędy ... Autonomia!Tablice są w zasadzie takie same jak wskaźniki w C / C ++, ale nie do końca. Po przekonwertowaniu tablicy:
do wskaźnika (który działa bez rzutowania, a zatem może się zdarzyć nieoczekiwanie w niektórych przypadkach):
tracisz zdolność
sizeof
operatora do zliczania elementów w tablicy:Tę utraconą zdolność określa się jako „rozkład”.
Aby uzyskać więcej informacji, zapoznaj się z tym artykułem o rozkładzie macierzy .
źródło
Oto, co mówi standard (C99 6.3.2.1/3 - Inne operandy - Wartości, tablice i desygnatory funkcji):
Oznacza to, że prawie za każdym razem, gdy nazwa tablicy jest używana w wyrażeniu, jest ona automatycznie konwertowana na wskaźnik do pierwszego elementu w tablicy.
Zauważ, że nazwy funkcji działają w podobny sposób, ale wskaźniki funkcji są używane znacznie rzadziej i w bardziej wyspecjalizowany sposób, że nie powoduje to prawie tyle zamieszania, co automatyczna konwersja nazw tablic na wskaźniki.
Standard C ++ (4.2 konwersja tablic na wskaźniki) rozluźnia wymaganie konwersji do (wyróżnienie moje):
Tak więc konwersja nie musi się odbywać tak, jak zawsze w C (pozwala to na przeciążenie funkcji lub dopasowanie szablonów do typu tablicy).
Dlatego też w C należy unikać używania parametrów tablic w prototypach / definicjach funkcji (moim zdaniem - nie jestem pewien, czy istnieje jakakolwiek ogólna zgoda). Powodują zamieszanie i są fikcją - użyj parametrów wskaźnika, a zamieszanie może nie zniknąć całkowicie, ale przynajmniej deklaracja parametru nie kłamie.
źródło
char x[] = "Hello";
. Szereg 6 elementów"Hello"
nie ulega rozpadowi; zamiast tegox
otrzymuje rozmiar,6
a jego elementy są inicjowane z elementów"Hello"
.„Rozpad” odnosi się do niejawnej konwersji wyrażenia z typu tablicowego na typ wskaźnika. W większości kontekstów, gdy kompilator widzi wyrażenie tablicowe, konwertuje typ wyrażenia z „tablicy N-elementowej T” na „wskaźnik do T” i ustawia wartość wyrażenia na adres pierwszego elementu tablicy . Wyjątki od tej reguły są przypadki, gdy tablica jest operand się z tych
sizeof
lub&
operatorów, czy tablica jest ciągiem dosłowne używany jako inicjator w deklaracji.Załóżmy następujący kod:
Wyrażenie
a
jest typu „80-elementowa tablica char”, a wyrażenie „This is a test” jest typu „16-elementowa tablica char” (w C; w C ++ literały łańcuchowe to tablice const char). Jednak w wywołaniu dostrcpy()
żadne wyrażenie nie jest operandemsizeof
lub&
, więc ich typy są domyślnie konwertowane na „wskaźnik na char”, a ich wartości są ustawiane na adres pierwszego elementu w każdym z nich. Costrcpy()
otrzymuje nie są tablice, ale wskaźniki, co widać w jego prototypu:To nie to samo, co wskaźnik tablicowy. Na przykład:
Zarówno
ptr_to_first_element
iptr_to_array
mają taką samą wartość ; adres bazowy Są to jednak różne typy i są traktowane inaczej, jak pokazano poniżej:Pamiętaj, że wyrażenie
a[i]
jest interpretowane jako*(a+i)
(który działa tylko wtedy, gdy typ tablica jest przekształcany do typu wskaźnika), tak jaka[i]
iptr_to_first_element[i]
działają tak samo. Wyrażenie(*ptr_to_array)[i]
jest interpretowane jako*(*a+i)
. Wyrażenia*ptr_to_array[i]
iptr_to_array[i]
mogą prowadzić do ostrzeżeń lub błędów kompilatora w zależności od kontekstu; na pewno zrobią coś złego, jeśli oczekujesz od nich ocenya[i]
.Ponownie, gdy tablica jest operandem
sizeof
, nie jest konwertowana na typ wskaźnika.ptr_to_first_element
jest prostym wskaźnikiem do char.źródło
"This is a test" is of type "16-element array of char"
"15-element array of char"
Tablice w C nie mają wartości.
Wszędzie tam, gdzie oczekiwana jest wartość obiektu, ale obiekt jest tablicą, używany jest adres jego pierwszego elementu z typem
pointer to (type of array elements)
.W funkcji wszystkie parametry są przekazywane przez wartość (tablice nie są wyjątkiem). Gdy przekazujesz tablicę w funkcji, „rozkłada się ona na wskaźnik” (sic); kiedy porównasz tablicę do czegoś innego, znowu „rozpada się ona na wskaźnik” (sic); ...
Funkcja foo oczekuje wartości tablicy. Ale w C tablice nie mają żadnej wartości! Więc
foo
dostaje zamiast adres pierwszego elementu tablicy.W powyższym porównaniu
arr
nie ma wartości, więc staje się wskaźnikiem. Staje się wskaźnikiem do int. Ten wskaźnik można porównać ze zmiennąip
.W składni indeksowania tablic, do której jesteś przyzwyczajony, znowu arr jest „rozkładany na wskaźnik”
Tablica nie rozpada się na wskaźnik tylko wtedy, gdy jest operandem operatora sizeof, operatora & (adres operatora) lub literału łańcuchowego używanego do inicjalizacji tablicy znaków.
źródło
To kiedy gnije tablica i jest wskazywana ;-)
Właściwie to po prostu to, że jeśli chcesz gdzieś przekazać tablicę, ale zamiast niej jest przekazywany wskaźnik (bo kto, do diabła, przekazałby ci całą tablicę), ludzie mówią, że słaba tablica uległa rozkładowi na wskaźnik.
źródło
a + 1
.Rozkład tablicy oznacza, że kiedy tablica jest przekazywana jako parametr do funkcji, jest traktowana identycznie jak wskaźnik („rozpada się”).
Istnieją dwa powikłania lub wyjątki od powyższego.
Po pierwsze, w przypadku tablic wielowymiarowych w C i C ++ tracony jest tylko pierwszy wymiar. Wynika to z faktu, że tablice są ułożone w pamięci w sposób ciągły, więc kompilator musi znać wszystkie oprócz pierwszego wymiaru, aby móc obliczyć przesunięcia w tym bloku pamięci.
Po drugie, w C ++ możesz użyć szablonów, aby wydedukować rozmiar tablic. Microsoft używa tego dla wersji C ++ funkcji Secure CRT, takich jak strcpy_s , i możesz użyć podobnej sztuczki, aby niezawodnie uzyskać liczbę elementów w tablicy .
źródło
tl; dr: Kiedy użyjesz zdefiniowanej tablicy, faktycznie będziesz używać wskaźnika do jej pierwszego elementu.
A zatem:
arr[idx]
, tak naprawdę po prostu mówisz*(arr + idx)
.Sortuj wyjątki od tej reguły:
struct
.sizeof()
podaje rozmiar zajmowany przez tablicę, a nie rozmiar wskaźnika.źródło
Mogę śmiało myśleć, że istnieją cztery (4) sposoby przekazywania tablicy jako argumentu funkcji. Również tutaj jest krótki, ale działający kod dla twojego przeglądu.
Mógłbym również sądzić, że pokazuje to wyższość C ++ w porównaniu z C. Przynajmniej w odniesieniu (w zamierzeniu pun) przekazywania tablicy przez referencję.
Oczywiście istnieją wyjątkowo surowe projekty bez alokacji sterty, bez wyjątków i bez std :: lib. Można powiedzieć, że natywna obsługa macierzy w C ++ to kluczowa funkcja języka.
źródło