Czym jest rozkładanie tablicy?
Czym jest rozkładanie tablicy? Czy jest jakiś związek ze wskaźnikami tablicy?
8 answers
Mówi się, że tablice "rozpadają się" na wskaźniki. Tablica C++ zadeklarowana jako int numbers [5]
nie może być ponownie wskazana, tzn. nie można powiedzieć numbers = 0x5a5aff23
. Co ważniejsze, termin rozpad oznacza utratę typu i wymiaru; numbers
rozpad na int*
poprzez utratę informacji o wymiarze (count 5), A Typ nie jest już int [5]
. Poszukaj tutaj przypadków, w których rozpad nie następuje .
Jeśli przekazujesz tablicę według wartości, tak naprawdę kopiujesz wskaźnik - wskaźnik do pierwszej tablicy element jest kopiowany do parametru (którego typ powinien być również wskaźnikiem typu elementu tablicy). Działa to ze względu na rozkładający się charakter tablicy; raz rozkładany, sizeof
nie daje już pełnej wielkości tablicy, ponieważ zasadniczo staje się wskaźnikiem. Dlatego preferowane jest (między innymi) przechodzenie przez odniesienie lub wskaźnik.
Trzy sposoby przejścia w tablicy1:
void by_value(const T* array) // const T array[] means the same
void by_pointer(const T (*array)[U])
void by_reference(const T (&array)[U])
Ostatnie dwa dadzą właściwe sizeof
informacje, natomiast pierwsze nie od argumentu array został uszkodzony, aby przypisać go do parametru.
1 stała U powinna być znana w czasie kompilacji.
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
2017-05-23 11:55:18
Tablice są zasadniczo takie same jak wskaźniki W C/C++, ale nie do końca. Po przekonwertowaniu tablicy:
const int a[] = { 2, 3, 5, 7, 11 };
Do wskaźnika (który działa bez rzucania, a zatem może się zdarzyć nieoczekiwanie w niektórych przypadkach):
const int* p = a;
Tracisz zdolność operatora sizeof
do liczenia elementów w tablicy:
assert( sizeof(p) != sizeof(a) ); // sizes are not equal
Ta utracona zdolność nazywana jest "rozpadem".
Aby uzyskać więcej informacji, zajrzyj do tego artykułu o rozkładach tablic.
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
2016-03-23 23:04:32
Oto, co mówi standard (C99 6.3.2.1 / 3-Inne operandy-Lvalues, tablice i desygnatory funkcji):
Z wyjątkiem sytuacji, gdy jest operandem operatora sizeof lub operatora uniary&, lub jest ciąg znaków używany do inicjalizacji tablicy, wyrażenie, które ma typ "array of type" jest konwertowane do wyrażenia z typem "wskaźnik do typu", które wskazuje na początkowy element obiekt array i nie jest lvalue.
Oznacza to, że prawie za każdym razem, gdy w wyrażeniu zostanie użyta nazwa tablicy, zostanie ona automatycznie przekonwertowana na wskaźnik do 1. pozycji w tablicy.
Zauważ, że nazwy funkcji działają w podobny sposób, ale Wskaźniki funkcji są używane znacznie rzadziej i w znacznie bardziej wyspecjalizowany sposób, że nie powoduje to prawie tak dużego zamieszania, jak automatyczna konwersja nazw tablic na wskaźniki.
Standard C++ (Konwersja Array-to-pointer 4.2) rozluźnia wymóg konwersji do (podkreślenia):
An wartość lvalue lub rvalue typu "array of N T "lub" array of unknown bound of t " Może zostać przekonwertowana na wartość R typu "wskaźnik do T."
Więc konwersja Nie musi przebiegać tak, jak zwykle w C(pozwala to na przeciążenie funkcji lub dopasowanie szablonów na typ tablicy).
Dlatego też w C należy unikać używania parametrów tablicy w prototypach funkcji/definicjach(moim zdaniem-nie jestem pewien czy jest jakaś ogólna zgoda). Oni powodują zamieszanie i są fikcją-użyj parametrów wskaźnika, a zamieszanie może nie zniknąć całkowicie, ale przynajmniej deklaracja parametrów nie kłamie.
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
2009-09-22 19:46:58
"Decay" odnosi się do niejawnej konwersji wyrażenia z typu tablicy na typ wskaźnika. W większości kontekstów, gdy kompilator widzi wyrażenie tablicowe, konwertuje typ wyrażenia z "tablicy N-elementów T" na "wskaźnik do T" i ustawia wartość wyrażenia na adres pierwszego elementu tablicy. Wyjątki od tej reguły są takie, gdy tablica jest operandem operatorów sizeof
lub &
, lub tablica jest literałem łańcuchowym używanym jako inicjalizacja w deklaracji.
Przyjmij następujący kod:
char a[80];
strcpy(a, "This is a test");
Wyrażenie a
jest typu "80-element array of char", a wyrażenie" This is a test "jest typu" 16-element array of char " (w C; w C++ literały łańcuchowe są tablicami const char). Jednak w wywołaniu strcpy()
żadne z wyrażeń nie jest operandem sizeof
lub &
, więc ich typy są domyślnie konwertowane na "wskaźnik na znak", a ich wartości są ustawiane na adres pierwszego elementu w każdym z nich. To, co strcpy()
otrzymuje nie są tablicami, ale wskaźnikami, jak widać w prototypie:
char *strcpy(char *dest, const char *src);
To nie to samo co wskaźnik tablicy. Na przykład:
char a[80];
char *ptr_to_first_element = a;
char (*ptr_to_array)[80] = &a;
Zarówno ptr_to_first_element
, jak i ptr_to_array
mają tę samą } wartość; adres bazowy a. są to jednak różne typy i są traktowane inaczej, jak pokazano poniżej:
a[i] == ptr_to_first_element[i] == (*ptr_to_array)[i] != *ptr_to_array[i] != ptr_to_array[i]
Pamiętaj, że wyrażenie {[15] } jest interpretowane jako *(a+i)
(co działa tylko wtedy, gdy typ tablicy jest przekonwertowany na typ wskaźnika), więc zarówno 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ń kompilatora lub błędów w zależności od kontekstu; na pewno zrobią coś złego, jeśli oczekujesz, że będą oceniać do 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) == 1
sizeof ptr_to_first_element == sizeof (char *) == whatever the pointer size
is on your platform
ptr_to_first_element
jest prostym wskaźnikiem do znaku.
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
2009-09-22 20:21:27
tablice w C nie mają wartości.
Wszędzie tam, gdzie oczekiwana jest wartość obiektu, ale obiekt jest tablicą, używany jest adres pierwszego elementu, z typem pointer to (type of array elements)
.
W funkcji wszystkie parametry są przekazywane przez wartość(tablice nie są wyjątkiem). Kiedy przekazujesz tablicę w funkcji, " rozkłada się ona na wskaźnik "(sic); kiedy porównujesz tablicę do czegoś innego, ponownie" rozkłada się na wskaźnik " (sic); ...
void foo(int arr[]);
Funkcja foo oczekuje wartości tablica. Ale w C tablice nie mają wartości! Tak więc foo
pobiera adres pierwszego elementu tablicy.
int arr[5];
int *ip = &(arr[1]);
if (arr == ip) { /* something; */ }
W porównaniu powyżej, arr
nie ma wartości, więc staje się wskaźnikiem. Staje się wskaźnikiem do int. Wskaźnik ten można porównać ze zmienną ip
.
W składni indeksowania tablicy, do której jesteś przyzwyczajony, arr jest 'rozkładany do wskaźnika'
arr[42];
/* same as *(arr + 42); */
/* same as *(&(arr[0]) + 42); */
Tablica nie rozpada się na wskaźnik tylko wtedy, gdy jest operandem Operator sizeof, lub operator & ('adres' Operatora), lub jako ciąg znaków używany do inicjalizacji tablicy znaków.
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
2009-09-22 17:55:23
To kiedy tablica gnije i jest wskazywana; -)
Właściwie, chodzi o to, że jeśli chcesz przekazać tablicę gdzieś, ale wskaźnik jest przekazywany zamiast tego (bo kto do diabła przekazałby całą tablicę za Ciebie), Ludzie mówią, że słaba tablica rozpadła się na wskaźnik.
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
2009-09-22 17:28:58
Rozkładanie tablicy oznacza, że gdy tablica jest przekazywana jako parametr do funkcji, jest traktowana identycznie jak ("rozkłada się do") wskaźnik.
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ą dwie komplikacje lub wyjątki od powyższego.
Po pierwsze, gdy mamy do czynienia z tablicami wielowymiarowymi w C i C++, traci się tylko pierwszy wymiar. Dzieje się tak dlatego, że tablice są rozmieszczone w pamięci, więc kompilator musi znać wszystkie oprócz pierwszego wymiaru, aby móc obliczyć przesunięcia w tym bloku pamięć.
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);
return 0;
}
Po drugie, w C++, można użyć szablonów, aby wydedukować rozmiar tablic. Microsoft używa tego do wersji C++ bezpiecznych funkcji CRT, takich jak strcpy_s , i możesz użyć podobnej sztuczki, aby niezawodnie uzyskać liczbę elementów w tablicy.
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
2018-05-21 08:49:27
TL;dr: kiedy używasz tablicy, którą zdefiniowałeś, będziesz używał wskaźnika do jej pierwszego elementu.
Tak więc:
- kiedy piszesz
arr[idx]
tak naprawdę mówisz*(arr + idx)
. - Funkcje nigdy tak naprawdę nie przyjmują tablic jako parametrów, tylko wskaźniki, nawet jeśli podasz parametr tablicy.
Rodzaj wyjątków od tej reguły:
- można przekazywać tablice o stałej długości do funkcji w obrębie
struct
. -
sizeof()
daje rozmiar wzięty przez tablica, a nie wielkość wskaźnika.
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
2018-03-13 09:59:08