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



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.

Question

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.




Come 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 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" .




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 []"?




In caso di:

char *x = "fred";

x è un lvalue - può essere assegnato a. Ma nel caso di:

char x[] = "fred";

x non è un lvalue, è un valore rval - non puoi assegnarlo.




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 assegnata all'avvio del programma e rimane assegnata 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.






Related