string Qual è la differenza tra char s [] e char * s?




6 Answers

Prima di tutto, negli argomenti di funzione, sono esattamente equivalenti:

void foo(char *x);
void foo(char x[]); // exactly the same in all respects

In altri contesti, char * alloca un puntatore, mentre char [] alloca una matrice. Dove finisce la stringa nel primo caso, chiedi? Il compilatore alloca segretamente una matrice anonima statica per contenere la stringa letterale. Così:

char *x = "Foo";
// is approximately equivalent to:
static const char __secret_anonymous_array[] = "Foo";
char *x = (char *) __secret_anonymous_array;

Nota che non devi mai tentare di modificare il contenuto di questo array anonimo tramite questo puntatore; gli effetti non sono definiti (spesso si intende un arresto):

x[1] = 'O'; // BAD. DON'T DO THIS.

L'uso della sintassi dell'array lo assegna direttamente alla nuova memoria. Quindi la modifica è sicura:

char x[] = "Foo";
x[1] = 'O'; // No problem.

Tuttavia, la matrice dura solo fino al suo ambito di applicazione, quindi se lo fai in una funzione, non restituire o perdere un puntatore a questo array - crea una copia invece con strdup() o simile. Se l'array è allocato in ambito globale, ovviamente, nessun problema.

c string char constants

In C, si può usare una stringa letterale in una dichiarazione come questa:

char s[] = "hello";

o in questo modo:

char *s = "hello";

Quindi qual è la differenza? Voglio sapere cosa succede realmente in termini di durata dello storage, sia in fase di compilazione che in fase di esecuzione.




Date le dichiarazioni

char *s0 = "hello world";
char s1[] = "hello world";

assumere la seguente ipotetica mappa di memoria:

                    0x01  0x02  0x03  0x04
        0x00008000: 'h'   'e'   'l'   'l'
        0x00008004: 'o'   ' '   'w'   'o'
        0x00008008: 'r'   'l'   'd'   0x00
        ...
s0:     0x00010000: 0x00  0x00  0x80  0x00
s1:     0x00010004: 'h'   'e'   'l'   'l'
        0x00010008: 'o'   ' '   'w'   'o'
        0x0001000C: 'r'   'l'   'd'   0x00

La stringa letterale "hello world" è una matrice di char di 12 elementi ( const char in C ++) con durata di archiviazione statica, il che significa che la memoria viene allocata all'avvio del programma e rimane allocata fino alla fine del programma. Il tentativo di modificare il contenuto di una stringa letterale richiama il comportamento non definito.

La linea

char *s0 = "hello world";

definisce s0 come puntatore al char con durata della memorizzazione automatica (ovvero la variabile s0 esiste solo per l'ambito in cui è dichiarata) e copia l' indirizzo della stringa letterale ( 0x00008000 in questo esempio) su di esso. Si noti che poiché s0 punta a un letterale stringa, non dovrebbe essere usato come argomento per qualsiasi funzione che proverebbe a modificarlo (ad esempio, strtok() , strcat() , strcpy() , ecc.).

La linea

char s1[] = "hello world";

definisce s1 come una matrice di char di 12 elementi (la lunghezza viene ricavata dalla stringa letterale) con la durata della memorizzazione automatica e copia il contenuto del letterale nella matrice. Come puoi vedere dalla mappa della memoria, abbiamo due copie della stringa "hello world" ; la differenza è che puoi modificare la stringa contenuta in s1 .

s0 e s1 sono intercambiabili nella maggior parte dei contesti; ecco le eccezioni:

sizeof s0 == sizeof (char*)
sizeof s1 == 12

type of &s0 == char **
type of &s1 == char (*)[12] // pointer to a 12-element array of char

È possibile riassegnare la variabile s0 in modo che punti a un letterale stringa diverso oa un'altra variabile. Non è possibile riassegnare la variabile s1 in modo che punti a un altro array.




char s[] = "hello";

dichiara che s è un array di char che è abbastanza lungo da contenere l'inizializzatore (5 + 1 char ) e inizializza l'array copiando i membri della stringa letterale specificata nell'array.

char *s = "hello";

dichiara s di essere un puntatore a uno o più (in questo caso più) char e lo punta direttamente in una posizione fissa (di sola lettura) contenente il letterale "hello" .




In aggiunta, considera che, come per gli scopi di sola lettura, l'uso di entrambi è identico, puoi accedere a un carattere indicizzando con il formato [] o *(<var> + <index>) :

printf("%c", x[1]);     //Prints r

E:

printf("%c", *(x + 1)); //Prints r

Ovviamente, se provi a farlo

*(x + 1) = 'a';

Probabilmente otterrai un errore di segmentazione, mentre stai tentando di accedere alla memoria di sola lettura.




char *str = "Hello";

Il precedente set str per puntare al valore letterale "Hello" che è hardcoded nell'immagine binaria del programma, che è contrassegnato come read-only in memoria, significa che qualsiasi modifica in questo letterale String è illegale e che genererebbe errori di segmentazione.

char str[] = "Hello";

copia la stringa nella memoria appena allocata nello stack. In questo modo qualsiasi modifica è consentita e legale.

means str[0] = 'M';

cambierà lo str in "Mello".

Per maggiori dettagli, passare alla domanda simile:

Perché ottengo un errore di segmentazione durante la scrittura su una stringa inizializzata con "char * s" ma non "char s []"?




Alla luce dei commenti qui dovrebbe essere ovvio che: char * s = "ciao"; È una cattiva idea e dovrebbe essere usato in ambito molto ristretto.

Questa potrebbe essere una buona opportunità per sottolineare che "la correttezza costante" è una "buona cosa". Quando e dove puoi, usa la parola chiave "const" per proteggere il tuo codice, da "rilassati" chiamanti o programmatori, che di solito sono più "rilassati" quando i puntatori entrano in gioco.

Basta il melodramma, ecco cosa si può ottenere quando adornano i puntatori con "const". (Nota: è necessario leggere le dichiarazioni dei puntatori da destra a sinistra.) Ecco i 3 diversi modi per proteggersi quando si gioca con i puntatori:

const DBJ* p means "p points to a DBJ that is const" 

- cioè, l'oggetto DBJ non può essere modificato tramite p.

DBJ* const p means "p is a const pointer to a DBJ" 

- ovvero, è possibile modificare l'oggetto DBJ tramite p, ma non è possibile modificare il puntatore p stesso.

const DBJ* const p means "p is a const pointer to a const DBJ" 

- cioè, non è possibile modificare il puntatore p stesso, né è possibile modificare l'oggetto DBJ tramite p.

Gli errori relativi alle mutazioni costanti tentate vengono catturati in fase di compilazione. Non c'è spazio di runtime o penalità di velocità per const.

(Supponiamo che stai usando il compilatore C ++, ovviamente?)

--DBJ




Related