2015-10-16 9 views
28

Se io dichiaro e utilizzare un puntatore come questo:Perché è possibile utilizzare puntatori come stringhe quando vengono dichiarati con virgolette doppie, ma non parentesi graffe, in C?

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

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

visualizza l'intera stringa e le opere e sì e c'è molto gioia.

Tuttavia, se uso un inizializzatore come questo:

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]); 

il programma si blocca e pCow rifiuta di muggire per il mio piacere edonistico!

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 

Testato con entusiasmo in Eclipse CDT.

+3

Se questa è la C (e non C++) allora 'char * pCow = (char []) { 'p', 'C', 'o', 'w','', 'g', 'o' , 'e', ​​'s', '', 'M', 'O', 'O', '\ 0'}; 'dovrebbe funzionare e avere lo stesso effetto. – immibis

+0

Si noti che la soluzione @immibis sopra ↑ richiede C99 o superiore. Cerca su _Compound Literals_ per saperne di più. –

+1

Eventuali duplicati di [stringhe letterali vs array di char durante l'inizializzazione di un puntatore] (http://stackoverflow.com/questions/30533439/string-literals-vs-array-of-char-when-initializing-a-pointer) –

risposta

40

In questo caso, pCow è impostato l'indirizzo di una c-stringa nella memoria statica:

char *pCow = "pCow goes MOO"; 

In questo caso, pCow è impostato al valore 'p' (cioè, 112):

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

Poiché l'indirizzo 112 punta più probabilmente in una memoria limitata/non valida, ciò causa l'esplosione del programma quando si tenta di accedere a pCow[counter].

L'avvertimento "elementi in eccesso nel initializer scalare" vi sta dicendo che è ignorando tutte le cose dopo il 'p' dal momento che il puntatore ha bisogno di un solo valore.

L'avvertimento "inizializzazione rende puntatore da interi senza un cast" sta dicendo che si sta utilizzando 'p' come puntatore, che probabilmente non è una buona idea ...

ciò che si vuole fare è dichiarare pCow come un array di caratteri piuttosto che un puntatore carattere se si desidera utilizzare la sintassi inizializzatore:

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

Ha senso. Grazie! sei attraente. : | (non posso accettare come risposta, ma il pulsante non farà clic. Tornerò ad esso!) –

+2

@JawiMmm - Sì, [lo fanno apposta] (http://meta.stackexchange.com/questions/50697/termine-on-accettare-una-risposta). In ogni caso, sono contento che questo ti abbia aiutato! Su una nota separata, [usare un 'char *' per puntare a un letterale c-string non è una buona idea neanche] (http://stackoverflow.com/questions/16767042/deprecated-conversion-from-string-constant -to-char-in-c? lq = 1) (dovresti usare invece 'const char *'). – DaoWen

+0

Notate la differenza qui: usando 'char []' crea l'array come variabile locale e copia i dati statici su di esso, mentre 'char *' crea un puntatore come variabile locale, che quindi può puntare a dati statici senza copiare nulla (che è il motivo per cui vuoi che 'const char *' punti a stringhe letterali). – hyde

11

"pCow goes MOO" è una stringa l iteral e hanno due diversi usi. O si può utilizzare come un inizializzatore ad un array:

char aCow[] = "pCow goes MOO"; 

Nel qual caso il contenuto della stringa letterale vengono copiati nella matrice.

In alternativa, è possibile utilizzare una stringa letterale come array costante autonomo in qualsiasi punto del programma. Ad esempio . Quindi c'è una differenza distintiva tra questi due:

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

Nel primo caso, il letterale viene copiato nell'array. Nel secondo caso, il letterale rimane una costante autonoma nella memoria di sola lettura, a cui puntiamo con un puntatore. Il primo può essere modificato, il secondo no.

Per quanto riguarda il caso di

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

Si utilizza un puntatore, ma non avete stringa letterale. Invece hai una lista di inizializzatori pensata per un array. Un buon compilatore ti avviserà per "inizializzatore in eccesso". Il motivo per cui il codice viene compilato è una regola molto strana in C che consente l'inizializzazione di variabili semplici con parentesi, ad esempio int x = {1};. Quindi il compilatore utilizza questa regola per inizializzare il puntatore in modo che punti all'indirizzo 'p', che è ovviamente privo di senso, e quindi scarta il resto dell'elenco di inizializzazione.