2015-10-16 19 views
28

Gdybym zadeklarować i użyć wskaźnika takiego:Dlaczego można używać wskaźników jako ciągów, gdy są one zadeklarowane z podwójnymi cudzysłowami, ale bez nawiasów klamrowych, w C?

int counter; 
char *pCow = "pCow goes MOO"; 

for(counter = 0; counter < 14; counter++) 
    printf("%c", pCow[counter]); 

wyświetla cały ciąg i prace i tak i nie ma dużo radości.

Jednakże, jeśli mogę użyć inicjator takiego:

int counter; 
char *pCow = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'}; 

for(counter = 0; counter < 14; counter++) 
    printf("%c", pCow[counter]); 

do awarii programu i pCow odmawia moo dla mojego hedonistycznej przyjemności!

3 Warnings. 0 Errors 
line 11 (near initialization for 'pCow') [enabled by default] C/C++ Problem 
line 11 excess elements in scalar initializer [enabled by default] C/C++ Problem 
line 11 initialization makes pointer from integer without a cast [enabled by default] C/C++ Problem 

Pięknie przetestowany w Eclipse CDT.

+3

Jeśli jest to C (a nie C++), to 'char * pCow = (char []) {'p', 'C', 'o', 'w', '', 'g', 'o' , 'e', ​​'s', '', 'M', 'O', 'O', '\ 0'}; 'powinny działać i mieć taki sam efekt. – immibis

+0

Należy zauważyć, że rozwiązanie @immibis powyżej ↑ wymaga C99 lub więcej. Sprawdź w _Compound Literals_, aby dowiedzieć się więcej na ten temat. –

+1

Możliwy duplikat [Literały łańcuchowe vs tablica znaków przy inicjalizacji wskaźnika] (http://stackoverflow.com/questions/30533439/string-literals-vs-array-of-char-when-initializing-a-pointer) –

Odpowiedz

40

W tym przypadku pCow jest ustawiony na adres C-string w pamięci statycznej:

char *pCow = "pCow goes MOO"; 

W tym przypadku pCow jest ustawiona na wartość 'p' (tj 112):

char *pCow = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'}; 

Ponieważ adres 112 najprawdopodobniej wskazuje na pamięć ograniczoną/nieważną, powoduje to, że program ulega awarii podczas próby uzyskania dostępu do pCow[counter].

Ostrzeżenia "Nadmiar elementów inicjalizatora skalarnego" mówi, że ignoruje wszystkie elementy po 'p', ponieważ wskaźnik potrzebuje tylko jednej wartości.

Ostrzeżenie „inicjalizacji sprawia wskaźnik z liczbą całkowitą bez oddanych” mówi ci, że używasz 'p' jako wskaźnik, który prawdopodobnie nie jest dobrym pomysłem ...

Co chcesz zrobić, to zadeklarować pCow jako tablica znaków niż wskaźnik znaków jeśli chcesz użyć składni initializer:

char pCow[] = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'}; 
+0

Ma sens. Dzięki! jesteś seksowny. : | (nie można zaakceptować jako odpowiedzi, ale przycisk nie kliknie, wrócę do niego!) –

+2

@JawiMmm - Tak, [robią to celowo] (http://meta.stackexchange.com/questions/50697/time-limit-on-accepting-an-answer). W każdym razie cieszę się, że ci pomogło! W oddzielnej notatce, [używanie 'char *' do wskazywania literału c-string nie jest dobrym pomysłem] (http://stackoverflow.com/questions/16767042/deprecated-conversion-from-tring-constant -to-char-in-c? lq = 1) (zamiast tego powinieneś użyć 'const char *'). – DaoWen

+0

Zauważ różnicę tutaj: użycie 'char []' tworzy tablicę jako zmienną lokalną i kopiuje do niej statyczne dane, podczas gdy 'char *' tworzy wskaźnik jako zmienną lokalną, która może następnie wskazywać dane statyczne bez kopiowania czegokolwiek (dlatego chcesz, aby 'const char *' wskazywało literały łańcuchowe). – hyde

11

"pCow goes MOO" jest ciągiem l iteracyjne i mają dwa różne zastosowania. Albo można go użyć jako inicjatora do tablicy:

char aCow[] = "pCow goes MOO"; 

W takim przypadku treść napisu dosłownym są kopiowane do tablicy.

Lub alternatywnie można użyć literału ciągu jako niezależnej tablicy stałej w dowolnym miejscu w programie. Na przykład . Tak więc istnieje wyraźna różnica między tymi dwoma:

char aCow[] = "pCow goes MOO"; 
char* pCow = "pCow goes MOO"; 

W pierwszym przypadku literał jest kopiowany do tablicy. W drugim przypadku literał pozostaje niezależną stałą w pamięci tylko do odczytu, którą wskazujemy wskaźnikiem. Ten pierwszy można zmodyfikować, ten drugi nie.

Jak na razie

char *pCow = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'}; 

Używasz wskaźnik, ale nie masz ciąg dosłowne. Zamiast tego masz listę inicjalizacyjną przeznaczoną dla tablicy. Dobry kompilator ostrzegłby o "nadmiar inicjatora". Powodem kompilacji kodu jest bardzo dziwna reguła w C, która pozwala inicjować zwykłe zmienne za pomocą nawiasów klamrowych, na przykład int x = {1};. Tak więc kompilator używa tej reguły do ​​zainicjowania wskaźnika do punktu pod adresem 'p', co jest oczywiście nonsensem, a następnie odrzuca resztę listy inicjalizatorów.