Dlaczego adres tablicy jest równy jej wartości w C?

W poniższym bitu kodu wartości wskaźnika i adresy wskaźników różnią się zgodnie z oczekiwaniami.

Ale wartości tablic i adresy nie!

Jak to możliwe?

Wyjście

my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC
#include <stdio.h>

int main()
{
  char my_array[100] = "some cool string";
  printf("my_array = %p\n", my_array);
  printf("&my_array = %p\n", &my_array);

  char *pointer_to_array = my_array;
  printf("pointer_to_array = %p\n", pointer_to_array);
  printf("&pointer_to_array = %p\n", &pointer_to_array);

  printf("Press ENTER to continue...\n");
  getchar();
  return 0;
}
Author: phant0m, 2010-03-27

6 answers

Nazwa tablicy zwykle jest obliczana na adres pierwszego elementu tablicy, więc array i &array mają tę samą wartość (ale różne typy, więc array+1 i &array+1 będą Nie będą równe, jeśli tablica ma więcej niż 1 element długości).

Są od tego dwa wyjątki: gdy nazwa tablicy jest operandem sizeof lub unary & (address-of), nazwa odnosi się do samego obiektu array. Tak więc sizeof array daje rozmiar w bajtach całej tablicy, a nie rozmiar pointer.

Dla tablicy zdefiniowanej jako T array[size], będzie ona miała typ T *. Kiedy / jeśli ją zwiększasz, dostajesz się do następnego elementu w tablicy.

&array ocenia pod tym samym adresem, ale biorąc pod uwagę tę samą definicję, tworzy wskaźnik typu T(*)[size] - tzn. jest wskaźnikiem do tablicy, a nie do pojedynczego elementu. Jeśli ten wskaźnik zostanie zwiększony, doda on Rozmiar całej tablicy, a nie pojedynczego elementu. Na przykład z takim kodem:

char array[16];
printf("%p\t%p", (void*)&array, (void*)(&array+1));

Możemy spodziewaj się, że drugi wskaźnik będzie o 16 większy od pierwszego (ponieważ jest tablicą 16 znaków). Ponieważ %p Zwykle konwertuje wskaźniki w systemie szesnastkowym, może to wyglądać mniej więcej tak:

0x12341000    0x12341010
 229
Author: Jerry Coffin,
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
2012-09-14 22:18:01

To dlatego, że nazwa tablicy (my_array) różni się od wskaźnika do tablicy. Jest aliasem do adresu tablicy, a jej adres jest zdefiniowany jako adres samej tablicy.

Wskaźnik jest normalną zmienną C na stosie. W ten sposób możesz wziąć jego adres i uzyskać inną wartość niż adres, który przechowuje w środku.

Pisałem o tym temacie tutaj - proszę spojrzeć.

 32
Author: Eli Bendersky,
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-03-27 06:02:35

W C, gdy używasz nazwy tablicy w wyrażeniu (włączając przekazywanie jej do funkcji), chyba że jest to operand operatora address-of (&) lub operatora sizeof, to rozpada się na wskaźnik do pierwszego elementu.

Oznacza to, że w większości kontekstów {[2] } jest równoważne &array[0] zarówno w typie, jak i wartości.

W twoim przykładzie my_array mA typ char[100], który rozpada się na char* po przekazaniu go do printf.

&my_array has type char (*)[100] (wskaźnik do tablicy 100 char). Ponieważ jest to operand &, jest to jeden z przypadków, w których my_array nie ulega natychmiastowemu rozpadowi na wskaźnik do pierwszego elementu.

Wskaźnik do tablicy ma taką samą wartość adresu jak wskaźnik do pierwszego elementu tablicy, ponieważ obiekt array jest tylko ciągiem jej elementów, ale wskaźnik do tablicy ma inny typ niż wskaźnik do elementu tej tablicy. Jest to ważne, gdy wykonujesz arytmetykę wskaźników na dwóch typach pointer.

pointer_to_array mA typ char * - zainicjalizowany tak, aby wskazywał na pierwszy element tablicy, ponieważ my_array rozpada się w wyrażeniu inicjalizacyjnym - i &pointer_to_array mA typ char ** (wskaźnik do wskaźnika do char).

Z nich: my_array (po rozpadzie do char*), &my_array i pointer_to_array wszystkie wskazują bezpośrednio na tablicę lub pierwszy element tablicy, a więc mają tę samą wartość adresu.

 28
Author: CB Bailey,
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
2019-08-01 21:06:00

Powód, dla którego my_array i &my_array dają ten sam adres, można łatwo zrozumieć, patrząc na układ pamięci tablicy.

Załóżmy, że masz tablicę 10 znaków (zamiast 100 w kodzie).

char my_array[10];

Pamięć dla my_array wygląda tak:

+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array.

W C/C++ Tablica rozkłada się na wskaźnik do pierwszego elementu w wyrażeniu takim jak

printf("my_array = %p\n", my_array);

Jeśli sprawdzisz, gdzie leży pierwszy element tablicy, zobaczysz, że jej adres jest tym samym co adres tablicy:

my_array[0]
|
v
+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array[0].
 3
Author: R Sahu,
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
2015-02-17 22:10:28

W języku programowania B, który był bezpośrednim poprzednikiem C, wskaźniki i liczby całkowite były swobodnie wymienne. System zachowywałby się jak chociaż cała pamięć była gigantyczną tablicą. Każda nazwa zmiennej miała albo globalny lub adres względny stosu w związku z tym, dla każdej nazwy zmiennej jedyną rzeczą, którą kompilator musiał śledzić, było to, czy jest to zmienna globalna czy lokalna, oraz jej adres względem pierwszej zmiennej globalnej lub lokalnej.

Given a global deklaracja typu i; [nie było potrzeby określania typu, ponieważ wszystko było liczbą całkowitą/wskaźnikiem] będzie przetwarzana przez kompilator jako: address_of_i = next_global++; memory[address_of_i] = 0; i polecenie i++ będzie przetwarzane jako: memory[address_of_i] = memory[address_of_i]+1;.

Deklaracja taka jak arr[10]; zostanie przetworzona jako address_of_arr = next_global; memory[next_global] = next_global; next_global += 10;. Zauważ, że gdy tylko deklaracja została przetworzona, kompilator mógł natychmiast zapomnieć o arr jako tablicy. Wyrażenie arr[i]=6; będzie przetwarzane jako memory[memory[address_of_a] + memory[address_of_i]] = 6;. Kompilator nie dbałby o to, czy arr reprezentuje tablicę i i liczbę całkowitą lub odwrotnie. W rzeczy samej, Nie dbałoby to o to, czy są to obie tablice, czy obie liczby całkowite; z przyjemnością wygenerowałoby kod zgodnie z opisem, bez względu na to, czy wynikowe zachowanie byłoby użyteczne.

Jednym z celów języka programowania C było bycie w dużej mierze kompatybilnym z B. W B nazwa tablicy [zwanej w terminologii B "wektorem"] zidentyfikowała zmienną posiadającą wskaźnik, który był początkowo przypisany aby wskazać na pierwszy element alokacji o podanym rozmiarze, więc jeśli nazwa ta pojawi się na liście argumentów dla funkcji, funkcja otrzyma wskaźnik do wektora. Mimo że C dodało" rzeczywiste " typy tablic, których nazwa była sztywno związana z adresem alokacji, a nie ze zmienną wskaźnika, która początkowo wskazywałaby na alokację, tablice rozkładające się na wskaźniki sprawiły, że kod deklarujący tablicę typu C zachowuje się identycznie jak kod B deklarujący wektor a potem nigdy nie zmodyfikował zmiennej posiadającej jej adres.

 3
Author: supercat,
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
2015-09-14 17:43:57

Właściwie &myarray i myarray są adresami bazowymi.

Jeśli chcesz zobaczyć różnicę zamiast używać

printf("my_array = %p\n", my_array);
printf("my_array = %p\n", &my_array);

Użyj

printf("my_array = %s\n", my_array);
printf("my_array = %p\n", my_array);
 1
Author: Ravi Bisla,
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
2013-06-28 09:30:43