@Nava (i pst): tablica i & tablica [0] nie są tak naprawdę takie same. Przykład : sizeof (tablica) i sizeof (i tablica [0]) dają różne wyniki.
Thomas Padron-McCarthy
1
@Thomas się zgadza, ale jeśli chodzi o wskaźniki, po wyrejestrowaniu tablicy i & array [0], generują tę samą wartość z tablicy [0] .ie * array == array [0]. Nikt nie miał na myśli, że te dwa wskaźniki są takie same, ale w tym konkretnym przypadku (wskazując na pierwszy element) możesz także użyć nazwy tablicy.
Tablica jest tablicą, a wskaźnik jest wskaźnikiem, ale w większości przypadków nazwy tablic są konwertowane na wskaźniki. Często używanym terminem jest to, że rozpadają się na wskaźniki.
Oto tablica:
int a[7];
a zawiera miejsce na siedem liczb całkowitych i możesz umieścić wartość w jednej z nich za pomocą przypisania, takiego jak to:
a[3]=9;
Oto wskaźnik:
int*p;
pnie zawiera spacji dla liczb całkowitych, ale może wskazywać spację dla liczby całkowitej. Możemy na przykład ustawić go tak, aby wskazywał jedno z miejsc w tablicy a, na przykład pierwsze:
p =&a[0];
Co może być mylące, to że możesz również napisać to:
p = a;
Ten sposób nie skopiować zawartość tablicy ado wskaźnika p(cokolwiek to by znaczyło). Zamiast tego nazwa tablicya jest konwertowana na wskaźnik do pierwszego elementu. To zadanie robi to samo co poprzednie.
Teraz możesz używać pw podobny sposób jak tablicę:
p[3]=17;
Powodem tego jest to, że operator dereferencji tablicowej w C [ ]jest zdefiniowany w kategoriach wskaźników. x[y]oznacza: zacznij od wskaźnika x, przesuń yelementy do przodu po tym, na co wskazuje wskaźnik, a następnie weź wszystko, co tam jest. Używając składni arytmetycznej wskaźnika, x[y]można również zapisać jako*(x+y) .
Aby to działało z normalną tablicą, taką jak nasza a, nazwa aw a[3]musi najpierw zostać przekonwertowana na wskaźnik (do pierwszego elementu w a). Następnie wykonujemy 3 kroki do przodu i bierzemy wszystko, co tam jest. Innymi słowy: weź element w pozycji 3 w tablicy. (Który jest czwartym elementem w tablicy, ponieważ pierwszy ma numer 0.)
Podsumowując, nazwy tablic w programie C są (w większości przypadków) konwertowane na wskaźniki. Jednym wyjątkiem jest sytuacja, gdy używamy sizeofoperatora w tablicy. Gdyby aw tym kontekście został przekonwertowany na wskaźnik, sizeof adałby rozmiar wskaźnika, a nie rzeczywistej tablicy, co byłoby raczej bezużyteczne, więc w tym przypadku aoznacza samą tablicę.
Podobna automatyczna konwersja jest stosowana do wskaźników funkcji - functionpointer()i oba (*functionpointer)()oznaczają to samo, o dziwo.
Carl Norum
3
Nie zapytał, czy tablice i wskaźniki są takie same, ale czy nazwa tablicy jest wskaźnikiem
Ricardo Amores,
32
Nazwa tablicy nie jest wskaźnikiem. Jest to identyfikator zmiennej typu tablica, która ma niejawną konwersję na wskaźnik typu elementu.
Pavel Minaev
29
Poza sizeof()tym innym kontekstem, w którym nie ma zaniku tablicy-> wskaźnika, jest operator &- w powyższym przykładzie &abędzie to wskaźnik do tablicy 7 int, a nie wskaźnik do jednego int; to znaczy, będzie to jego typ int(*)[7], który nie może być domyślnie konwertowany na int*. W ten sposób funkcje mogą faktycznie pobierać wskaźniki do tablic o określonym rozmiarze i wymuszać ograniczenie za pomocą systemu typów.
Pavel Minaev
3
@ onmyway133, sprawdź tutaj, aby uzyskać krótkie wyjaśnienie i dalsze cytowania.
Carl Norum
36
Gdy tablica jest używana jako wartość, jej nazwa reprezentuje adres pierwszego elementu.
Gdy tablica nie jest używana jako wartość, jej nazwa reprezentuje całą tablicę.
int arr[7];/* arr used as value */
foo(arr);int x =*(arr +1);/* same as arr[1] *//* arr not used as value */size_t bytes =sizeof arr;void*q =&arr;/* void pointers are compatible with pointers to any object */
Jeśli wyrażenie typu tablicowego (takie jak nazwa tablicy) pojawia się w większym wyrażeniu i nie jest operandem operatora &lub sizeof, wówczas typ wyrażenia tablicowego jest konwertowany z „N-elementowej tablicy T” na „wskaźnik do T”, a wartością wyrażenia jest adres pierwszego elementu w tablicy.
Krótko mówiąc, nazwa tablicy nie jest wskaźnikiem, ale w większości kontekstów jest traktowana tak, jakby była wskaźnikiem.
Edytować
Odpowiedź na pytanie w komentarzu:
Jeśli używam sizeof, czy liczę rozmiar tylko elementów tablicy? Zatem tablica „head” również zajmuje miejsce z informacją o długości i wskaźniku (a to oznacza, że zajmuje więcej miejsca niż normalny wskaźnik)?
Gdy tworzysz tablicę, jedyną przydzieloną przestrzenią jest przestrzeń dla samych elementów; nie ma miejsca na przechowywanie osobnego wskaźnika lub jakichkolwiek metadanych. Dany
Wyrażeniea odnosi się do całej tablicy, ale nie ma obiektua oddzielnie od samych elementów macierzy. W ten sposób sizeof adaje rozmiar (w bajtach) całej tablicy. Wyrażenie &apodaje adres tablicy, który jest taki sam jak adres pierwszego elementu . Różnica między &ai &a[0]jest rodzajem wyniku 1 - char (*)[10]w pierwszym przypadku i char *w drugim.
Dziwnie się dzieje, gdy chcesz uzyskać dostęp do poszczególnych elementów - wyrażenie a[i]jest definiowane jako wynik *(a + i)- biorąc pod uwagę wartość adresu a, przesunąć ielementy ( nie bajty ) od tego adresu i wykluczyć wynik.
Problem polega na tym, że anie jest to wskaźnik ani adres - to cały obiekt tablicy. Zatem reguła w C, że ilekroć kompilator widzi wyrażenie typu tablicowego (takie jak a, który ma typ char [10]) i to wyrażenie nie jest operandem operatorów sizeofjednoargumentowych &, typ tego wyrażenia jest konwertowany („zanika”) na typ wskaźnika ( char *), a wartością wyrażenia jest adres pierwszego elementu tablicy. Dlatego wyrażeniea ma ten sam typ i wartość co wyrażenie &a[0](a przez rozszerzenie wyrażenie *ama ten sam typ i wartość co wyrażenie a[0]).
C pochodzi z wcześniejszej języku zwanym B, a B abył odrębny przedmiot wskaźnik z elementów tablicy a[0], a[1]itp Ritchie chce zachować semantykę tablicy B, ale nie chciał zadzierać z przechowywaniem oddzielny obiekt wskaźnika. Więc się tego pozbył. Zamiast tego kompilator konwertuje wyrażenia tablicowe na wyrażenia wskaźnika podczas tłumaczenia, jeśli to konieczne.
Pamiętaj, że powiedziałem, że tablice nie przechowują żadnych metadanych dotyczących ich wielkości. Gdy tylko wyrażenie tablicowe „rozpada się” na wskaźnik, wszystko, co masz, to wskaźnik na pojedynczy element. Ten element może być pierwszym z sekwencji elementów lub może być pojedynczym obiektem. Nie ma sposobu, aby wiedzieć na podstawie samego wskaźnika.
Gdy przekazujesz wyrażenie tablicowe do funkcji, wszystko, co funkcja odbiera, jest wskaźnikiem do pierwszego elementu - nie ma pojęcia, jak duża jest tablica (dlatego getsfunkcja była takim zagrożeniem i ostatecznie została usunięta z biblioteki). Aby funkcja wiedziała, ile elementów ma tablica, musisz albo użyć wartownika (np. Terminator 0 w łańcuchach C), albo przekazać liczbę elementów jako osobny parametr.
To, co * może * wpłynąć na interpretację wartości adresu - zależy od maszyny.
Długo szukałem tej odpowiedzi. Dziękuję Ci! A jeśli wiesz, czy mógłbyś powiedzieć nieco dalej, czym jest wyrażenie tablicowe. Jeśli używam sizeof, czy liczę rozmiar tylko elementów tablicy? Zatem tablica „head” również zajmuje miejsce z informacją o długości i wskaźniku (a to oznacza, że zajmuje więcej miejsca niż normalny wskaźnik)?
Andriy Dmytruk,
I jeszcze jedno. Tablica o długości 5 jest typu int [5]. Więc skąd znamy długość, gdy wywołujemy sizeof (tablica) - od jego typu? A to oznacza, że tablice o różnej długości są jak różne typy stałych?
Andriy Dmytruk,
@AndriyDmytruk: sizeofjest operatorem i oblicza liczbę bajtów w operandzie (albo wyrażenie oznaczające obiekt, albo nazwa typu w nawiasach). Tak więc, dla tablicy, sizeofocenia się liczbę elementów pomnożoną przez liczbę bajtów w jednym elemencie. Jeśli an intma szerokość 4 bajtów, 5-elementowa tablica intzajmuje 20 bajtów.
John Bode,
Czy operator [ ]też nie jest wyjątkowy? Na przykład int a[2][3];wtedy x = a[1][2];, chociaż można go przepisać jako x = *( *(a+1) + 2 );, tutaj anie jest konwertowany na typ wskaźnika int*(chociaż jeśli ajest argumentem funkcji, powinien zostać przekonwertowany int*).
Stan
2
@Stan: Wyrażenie ama typ int [2][3], który „rozpada się” na typ int (*)[3]. Wyrażenie *(a + 1)ma typ int [3], który „rozpada się” int *. Zatem *(*(a + 1) + 2)będzie miał typ int. awskazuje na pierwszym 3 elementu tablicy int, a + 1wskazuje na drugim 3 elementu tablicy int, *(a + 1)to drugi 3-elementowa tablica int, *(a + 1) + 2wskazuje trzeciego elementu drugiego układu int, tak *(*(a + 1) + 2)jest trzeci element drugi rząd int. Sposób mapowania na kod maszynowy zależy wyłącznie od kompilatora.
John Bode
5
Tablica zadeklarowana w ten sposób
int a[10];
przydziela pamięć na 10 ints. Nie możesz modyfikować, aale możesz wykonywać arytmetykę wskaźników a.
Taki wskaźnik przydziela pamięć tylko dla wskaźnika p:
int*p;
Nie przydziela żadnych ints. Możesz to zmienić:
p = a;
i używaj indeksów tablicowych, jak możesz, używając:
p[2]=5;
a[2]=5;// same*(p+2)=5;// same effect*(a+2)=5;// same effect
Tablice nie zawsze są przydzielane na stosie. Jest to szczegół implementacji, który różni się w zależności od kompilatora. W większości przypadków tablice statyczne lub globalne będą przydzielane z innego regionu pamięci niż stos. Tablice typów stałych mogą być przydzielane z jeszcze innego regionu pamięci
Mark Bessey,
1
Myślę, że Grumdrig chciał powiedzieć „przydziela 10 ints z automatycznym czasem przechowywania”.
Lekkość ściga się na orbicie
4
Sama nazwa tablicy daje miejsce w pamięci, więc możesz traktować nazwę tablicy jak wskaźnik:
int a[7];
a[0]=1976;
a[1]=1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a,*a);
I inne fajne rzeczy, które możesz zrobić, aby wskaźnik (np. Dodawanie / odejmowanie przesunięcia), możesz także zrobić z tablicą:
printf("value at memory location %p is %d", a +1,*(a +1));
Pod względem językowym, jeśli C nie ujawnił tablicy jako jakiegoś „wskaźnika” (pedantycznie jest to tylko lokalizacja pamięci. Nie może wskazywać na dowolną lokalizację w pamięci, ani nie może być kontrolowana przez programistę). Zawsze musimy to zakodować:
printf("value at memory location %p is %d",&a[1], a[1]);
Kompiluje dobrze (z 2 ostrzeżeniami) w gcc 4.9.2 i drukuje następujące:
a ==&a:1
ups :-)
Wniosek jest następujący: nie, tablica nie jest wskaźnikiem, nie jest przechowywana w pamięci (nawet tylko do odczytu) jako wskaźnik, nawet jeśli tak wygląda, ponieważ można uzyskać jego adres za pomocą operatora & . Ale - ups - ten operator nie działa :-)), tak czy inaczej, zostałeś ostrzeżony:
p.c:In function ‘main’:
pp.c:6:12: warning: initialization from incompatible pointer type
int**b =&a;^
p.c:8:28: warning: comparison of distinct pointer types lacks a cast
printf("a == &a: %d\n", a == b);
C ++ odrzuca wszelkie takie próby z błędami w czasie kompilacji.
„Kompiluje się dobrze (z 2 ostrzeżeniami)”. To nie w porządku. Jeśli powiesz gcc, aby skompilował go jako poprawny standard C przez dodanie -std=c11 -pedantic-errors, pojawi się błąd kompilatora podczas pisania nieprawidłowego kodu C. Powodem jest to, że próbujesz przypisać int (*)[3]zmienną int**, która jest dwoma typami, które absolutnie nie mają ze sobą nic wspólnego. Więc co ten przykład ma udowodnić, nie mam pojęcia.
Lundin
Dziękuję Lundin za komentarz. Wiesz, że istnieje wiele standardów. Próbowałem wyjaśnić, co miałem na myśli w tej edycji. Nie chodzi tu o int **typ, lepiej void *do tego użyć .
Palo,
-3
Nazwa tablicy zachowuje się jak wskaźnik i wskazuje na pierwszy element tablicy. Przykład:
int a[]={1,2,3};
printf("%p\n",a);//result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]);//result is similar to 0x7fff6fe40bc0
Obie instrukcje print dadzą dokładnie taką samą wydajność dla maszyny. W moim systemie dało to:
Tablica to zbiór poufnych i ciągłych elementów w pamięci. W C nazwa tablicy jest indeksem pierwszego elementu, a stosując przesunięcie można uzyskać dostęp do reszty elementów. „Indeks do pierwszego elementu” jest rzeczywiście wskaźnikiem kierunku pamięci.
Różnica między zmiennymi wskaźnikowymi polega na tym, że nie można zmienić lokalizacji, na którą wskazuje nazwa tablicy, więc jest podobny do wskaźnika stałej (jest podobny, a nie taki sam. Zobacz komentarz Marka). Ale także, że nie musisz odrywać nazwy tablicy, aby uzyskać wartość, jeśli używasz arytmetyki wskaźnika:
chararray="hello wordl";char* ptr =array;char c =array[2];//array[2] holds the character 'l'char*c1 = ptr[2];//ptr[2] holds a memory direction that holds the character 'l'
Nazwa tablicy nie jest taka sama jak wskaźnik const. Biorąc pod uwagę: int a [10]; int * p = a; sizeof (p) i sizeof (a) nie są takie same.
Mark Bessey
1
Istnieją inne różnice. Ogólnie rzecz biorąc, najlepiej trzymać się terminologii stosowanej przez standard C, który konkretnie nazywa to „konwersją”. Cytat: „Z wyjątkiem sytuacji, gdy jest to operand operatora sizeof lub unary & operator, lub jest literałem łańcuchowym używanym do inicjalizacji tablicy, wyrażenie o typie„ tablica typu ”jest konwertowane na wyrażenie typu„ „wskaźnik do typu”, który wskazuje na początkowy element obiektu tablicowego i nie jest wartością. Jeśli obiekt tablicowy ma klasę pamięci rejestru, zachowanie jest niezdefiniowane. ”
Pavel Minaev
-5
Nazwa tablicy to adres pierwszego elementu tablicy. Tak więc nazwa tablicy jest stałym wskaźnikiem.
&array[0]
zwraca wskaźnik, a nie tablicę;)Odpowiedzi:
Tablica jest tablicą, a wskaźnik jest wskaźnikiem, ale w większości przypadków nazwy tablic są konwertowane na wskaźniki. Często używanym terminem jest to, że rozpadają się na wskaźniki.
Oto tablica:
a
zawiera miejsce na siedem liczb całkowitych i możesz umieścić wartość w jednej z nich za pomocą przypisania, takiego jak to:Oto wskaźnik:
p
nie zawiera spacji dla liczb całkowitych, ale może wskazywać spację dla liczby całkowitej. Możemy na przykład ustawić go tak, aby wskazywał jedno z miejsc w tablicya
, na przykład pierwsze:Co może być mylące, to że możesz również napisać to:
Ten sposób nie skopiować zawartość tablicy
a
do wskaźnikap
(cokolwiek to by znaczyło). Zamiast tego nazwa tablicya
jest konwertowana na wskaźnik do pierwszego elementu. To zadanie robi to samo co poprzednie.Teraz możesz używać
p
w podobny sposób jak tablicę:Powodem tego jest to, że operator dereferencji tablicowej w C
[ ]
jest zdefiniowany w kategoriach wskaźników.x[y]
oznacza: zacznij od wskaźnikax
, przesuńy
elementy do przodu po tym, na co wskazuje wskaźnik, a następnie weź wszystko, co tam jest. Używając składni arytmetycznej wskaźnika,x[y]
można również zapisać jako*(x+y)
.Aby to działało z normalną tablicą, taką jak nasza
a
, nazwaa
wa[3]
musi najpierw zostać przekonwertowana na wskaźnik (do pierwszego elementu wa
). Następnie wykonujemy 3 kroki do przodu i bierzemy wszystko, co tam jest. Innymi słowy: weź element w pozycji 3 w tablicy. (Który jest czwartym elementem w tablicy, ponieważ pierwszy ma numer 0.)Podsumowując, nazwy tablic w programie C są (w większości przypadków) konwertowane na wskaźniki. Jednym wyjątkiem jest sytuacja, gdy używamy
sizeof
operatora w tablicy. Gdybya
w tym kontekście został przekonwertowany na wskaźnik,sizeof a
dałby rozmiar wskaźnika, a nie rzeczywistej tablicy, co byłoby raczej bezużyteczne, więc w tym przypadkua
oznacza samą tablicę.źródło
functionpointer()
i oba(*functionpointer)()
oznaczają to samo, o dziwo.sizeof()
tym innym kontekstem, w którym nie ma zaniku tablicy-> wskaźnika, jest operator&
- w powyższym przykładzie&a
będzie to wskaźnik do tablicy 7int
, a nie wskaźnik do jednegoint
; to znaczy, będzie to jego typint(*)[7]
, który nie może być domyślnie konwertowany naint*
. W ten sposób funkcje mogą faktycznie pobierać wskaźniki do tablic o określonym rozmiarze i wymuszać ograniczenie za pomocą systemu typów.Gdy tablica jest używana jako wartość, jej nazwa reprezentuje adres pierwszego elementu.
Gdy tablica nie jest używana jako wartość, jej nazwa reprezentuje całą tablicę.
źródło
Jeśli wyrażenie typu tablicowego (takie jak nazwa tablicy) pojawia się w większym wyrażeniu i nie jest operandem operatora
&
lubsizeof
, wówczas typ wyrażenia tablicowego jest konwertowany z „N-elementowej tablicy T” na „wskaźnik do T”, a wartością wyrażenia jest adres pierwszego elementu w tablicy.Krótko mówiąc, nazwa tablicy nie jest wskaźnikiem, ale w większości kontekstów jest traktowana tak, jakby była wskaźnikiem.
Edytować
Odpowiedź na pytanie w komentarzu:
Gdy tworzysz tablicę, jedyną przydzieloną przestrzenią jest przestrzeń dla samych elementów; nie ma miejsca na przechowywanie osobnego wskaźnika lub jakichkolwiek metadanych. Dany
masz w pamięci
Wyrażenie
a
odnosi się do całej tablicy, ale nie ma obiektua
oddzielnie od samych elementów macierzy. W ten sposóbsizeof a
daje rozmiar (w bajtach) całej tablicy. Wyrażenie&a
podaje adres tablicy, który jest taki sam jak adres pierwszego elementu . Różnica między&a
i&a[0]
jest rodzajem wyniku 1 -char (*)[10]
w pierwszym przypadku ichar *
w drugim.Dziwnie się dzieje, gdy chcesz uzyskać dostęp do poszczególnych elementów - wyrażenie
a[i]
jest definiowane jako wynik*(a + i)
- biorąc pod uwagę wartość adresua
, przesunąći
elementy ( nie bajty ) od tego adresu i wykluczyć wynik.Problem polega na tym, że
a
nie jest to wskaźnik ani adres - to cały obiekt tablicy. Zatem reguła w C, że ilekroć kompilator widzi wyrażenie typu tablicowego (takie jaka
, który ma typchar [10]
) i to wyrażenie nie jest operandem operatorówsizeof
jednoargumentowych&
, typ tego wyrażenia jest konwertowany („zanika”) na typ wskaźnika (char *
), a wartością wyrażenia jest adres pierwszego elementu tablicy. Dlatego wyrażeniea
ma ten sam typ i wartość co wyrażenie&a[0]
(a przez rozszerzenie wyrażenie*a
ma ten sam typ i wartość co wyrażeniea[0]
).C pochodzi z wcześniejszej języku zwanym B, a B
a
był odrębny przedmiot wskaźnik z elementów tablicya[0]
,a[1]
itp Ritchie chce zachować semantykę tablicy B, ale nie chciał zadzierać z przechowywaniem oddzielny obiekt wskaźnika. Więc się tego pozbył. Zamiast tego kompilator konwertuje wyrażenia tablicowe na wyrażenia wskaźnika podczas tłumaczenia, jeśli to konieczne.Pamiętaj, że powiedziałem, że tablice nie przechowują żadnych metadanych dotyczących ich wielkości. Gdy tylko wyrażenie tablicowe „rozpada się” na wskaźnik, wszystko, co masz, to wskaźnik na pojedynczy element. Ten element może być pierwszym z sekwencji elementów lub może być pojedynczym obiektem. Nie ma sposobu, aby wiedzieć na podstawie samego wskaźnika.
Gdy przekazujesz wyrażenie tablicowe do funkcji, wszystko, co funkcja odbiera, jest wskaźnikiem do pierwszego elementu - nie ma pojęcia, jak duża jest tablica (dlatego
gets
funkcja była takim zagrożeniem i ostatecznie została usunięta z biblioteki). Aby funkcja wiedziała, ile elementów ma tablica, musisz albo użyć wartownika (np. Terminator 0 w łańcuchach C), albo przekazać liczbę elementów jako osobny parametr.źródło
sizeof
jest operatorem i oblicza liczbę bajtów w operandzie (albo wyrażenie oznaczające obiekt, albo nazwa typu w nawiasach). Tak więc, dla tablicy,sizeof
ocenia się liczbę elementów pomnożoną przez liczbę bajtów w jednym elemencie. Jeśli anint
ma szerokość 4 bajtów, 5-elementowa tablicaint
zajmuje 20 bajtów.[ ]
też nie jest wyjątkowy? Na przykładint a[2][3];
wtedyx = a[1][2];
, chociaż można go przepisać jakox = *( *(a+1) + 2 );
, tutaja
nie jest konwertowany na typ wskaźnikaint*
(chociaż jeślia
jest argumentem funkcji, powinien zostać przekonwertowanyint*
).a
ma typint [2][3]
, który „rozpada się” na typint (*)[3]
. Wyrażenie*(a + 1)
ma typint [3]
, który „rozpada się”int *
. Zatem*(*(a + 1) + 2)
będzie miał typint
.a
wskazuje na pierwszym 3 elementu tablicyint
,a + 1
wskazuje na drugim 3 elementu tablicyint
,*(a + 1)
to drugi 3-elementowa tablicaint
,*(a + 1) + 2
wskazuje trzeciego elementu drugiego układuint
, tak*(*(a + 1) + 2)
jest trzeci element drugi rządint
. Sposób mapowania na kod maszynowy zależy wyłącznie od kompilatora.Tablica zadeklarowana w ten sposób
przydziela pamięć na 10
int
s. Nie możesz modyfikować,a
ale możesz wykonywać arytmetykę wskaźnikówa
.Taki wskaźnik przydziela pamięć tylko dla wskaźnika
p
:Nie przydziela żadnych
int
s. Możesz to zmienić:i używaj indeksów tablicowych, jak możesz, używając:
źródło
int
s z automatycznym czasem przechowywania”.Sama nazwa tablicy daje miejsce w pamięci, więc możesz traktować nazwę tablicy jak wskaźnik:
I inne fajne rzeczy, które możesz zrobić, aby wskaźnik (np. Dodawanie / odejmowanie przesunięcia), możesz także zrobić z tablicą:
Pod względem językowym, jeśli C nie ujawnił tablicy jako jakiegoś „wskaźnika” (pedantycznie jest to tylko lokalizacja pamięci. Nie może wskazywać na dowolną lokalizację w pamięci, ani nie może być kontrolowana przez programistę). Zawsze musimy to zakodować:
źródło
Myślę, że ten przykład rzuca nieco światła na ten problem:
Kompiluje dobrze (z 2 ostrzeżeniami) w gcc 4.9.2 i drukuje następujące:
ups :-)
Wniosek jest następujący: nie, tablica nie jest wskaźnikiem, nie jest przechowywana w pamięci (nawet tylko do odczytu) jako wskaźnik, nawet jeśli tak wygląda, ponieważ można uzyskać jego adres za pomocą operatora & . Ale - ups - ten operator nie działa :-)), tak czy inaczej, zostałeś ostrzeżony:
C ++ odrzuca wszelkie takie próby z błędami w czasie kompilacji.
Edytować:
Oto, co chciałem zademonstrować:
Mimo
c
ia
„wskaż” tę samą pamięć, możesz uzyskać adresc
wskaźnika, ale nie możesz uzyskać adresua
wskaźnika.źródło
-std=c11 -pedantic-errors
, pojawi się błąd kompilatora podczas pisania nieprawidłowego kodu C. Powodem jest to, że próbujesz przypisaćint (*)[3]
zmiennąint**
, która jest dwoma typami, które absolutnie nie mają ze sobą nic wspólnego. Więc co ten przykład ma udowodnić, nie mam pojęcia.int **
typ, lepiejvoid *
do tego użyć .Nazwa tablicy zachowuje się jak wskaźnik i wskazuje na pierwszy element tablicy. Przykład:
Obie instrukcje print dadzą dokładnie taką samą wydajność dla maszyny. W moim systemie dało to:
źródło
Tablica to zbiór poufnych i ciągłych elementów w pamięci. W C nazwa tablicy jest indeksem pierwszego elementu, a stosując przesunięcie można uzyskać dostęp do reszty elementów. „Indeks do pierwszego elementu” jest rzeczywiście wskaźnikiem kierunku pamięci.
Różnica między zmiennymi wskaźnikowymi polega na tym, że nie można zmienić lokalizacji, na którą wskazuje nazwa tablicy, więc jest podobny do wskaźnika stałej (jest podobny, a nie taki sam. Zobacz komentarz Marka). Ale także, że nie musisz odrywać nazwy tablicy, aby uzyskać wartość, jeśli używasz arytmetyki wskaźnika:
Więc odpowiedź brzmi „tak”.
źródło
Nazwa tablicy to adres pierwszego elementu tablicy. Tak więc nazwa tablicy jest stałym wskaźnikiem.
źródło