2011-10-02 15 views
21

W C dlaczego jest to zgodne z prawemwskaźnik w C

char * str = "Hello"; 

ale nielegalnej zrobić

int * arr = {0,1,2,3}; 
+0

powodują, że nie jest tablicą. (Standard nie określa, że ​​to działa.) –

+0

Ponieważ zwykle oczekujemy 'printf (" Hello, world! \ N ");' do pracy bez żadnych zmiennych, ale nikt nie chce używać 'memcpy (arr, {0} , 1,2,3}, sizeof arr); ' –

+2

@ChrisLutz: Kto mówi, że nikt nie chce? Nie używamy go, ponieważ język go nie obsługuje; pytanie (uzasadnione IMHO) brzmi: * dlaczego *. –

Odpowiedz

12

myślę, że to po prostu jak inicjalizatory pracy w C. Można jednak zrobić:

int *v = (int[]){1, 2, 3}; /* C99. */ 
+2

Możesz zrobić tę samą składnię dla ciągów, aby uzyskać modyfikowalny ciąg "literał". –

3

Ponieważ nie ma sensu deklarowanie i inicjowanie wskaźnika do tablicy int, gdy nazwa macierzy może być użyty jako wskaźnik do pierwszego elementu. Po

int arr[] = { 0, 1, 2, 3 }; 

można użyć arr jak int * prawie we wszystkich kontekstach (wyjątkiem jest jako argumentu do sizeof).

+6

Drugim wyjątkiem jest operand jednoargumentowego operatora adresu '&'; '& arr' podaje adres tablicy, a nie jej pierwszego elementu (tej samej lokalizacji pamięci, innego typu). –

8

chodzi o C89:

"A string", stosowane na zewnątrz char inicjalizacji tablicy, to Łańcuch znaków; standard mówi, że kiedy używasz literału łańcuchowego, to tak jakby utworzyć globalną tablicę char zainicjowaną do tej wartości i napisać jej nazwę zamiast literału (istnieje również dodatkowe ograniczenie, że każda próba modyfikacji literału ciągu skutkuje niezdefiniowanym zachowaniem) . W twoim kodzie zainicjujesz char * z literałem tekstowym, który rozpada się na wskaźnik char i wszystko działa poprawnie.

Jednakże, jeśli użyjesz literału łańcuchowego do zainicjowania tablicy char, kilka magicznych reguł zacznie działać, więc nie będzie już "jak gdyby tablica ... itd." (Która nie działałaby przy inicjalizacji tablicy), ale jest to po prostu dobry sposób poinformowania kompilatora, jak należy zainicjować tablicę.

Sposób zainicjowania tablic w postaci {1, 2, 3} zachowuje tylko tę wartość semantyczną: służy tylko do inicjalizacji tablicy, nie jest to "literał tablicowy".

5

W przypadku:

char * str = "Hello"; 

"Hello" jest ciągiem dosłowne. Jest ładowany do pamięci (ale często tylko do odczytu) podczas uruchamiania programu i ma adres pamięci, który można przypisać do wskaźnika takiego jak char *str. Takie literały łańcuchowe są jednak wyjątkiem.

Z:

int * arr = {0,1,2,3}; 

..you're skutecznie stara się wskazać na tablicy, które nie zostały wprowadzone w dowolnym miejscu w szczególności w pamięci. arr to wskaźnik, a nie tablica; posiada adres pamięci, ale sam nie ma pamięci dla danych tablicy. Jeśli użyjesz int arr[] zamiast int *arr, to działa, ponieważ taka tablica jest związana z przechowywaniem dla jej zawartości. Chociaż tablica rozpada się na wskaźnik do danych w wielu kontekstach, to nie to samo.

Nawet z literałami ciągów, char *str = "Hello"; i char str[] = "Hello"; robić różne rzeczy. Pierwszy ustawia wskaźnik str, aby wskazywał na literał łańcuchowy, a drugi inicjuje tablicę str z wartościami z "Hello".Tablica ma pamięć dla powiązanych z nią danych, ale wskaźnik po prostu wskazuje na dane, które są już wczytane do pamięci.

2

... czy można nadużywać literały ciągów znaków i zapisać jako ciąg cyfr dosłownym, który za niewielką maszynę endian będzie wyglądać następująco:

int * arr = (int *)"\0\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0"; 
+0

Mała maszyna endianowa, gdzie 'sizeof int' to 4, to by być precyzyjne. – Jens