2010-11-03 13 views
8

Eventuali duplicati:
strtok wont accept: char *strstrtok - array di caratteri rispetto puntatore char

Quando si utilizza la funzione di strtok, utilizzando un char * invece di un char [] risultati in un errore di segmentazione.

Questo viene eseguito correttamente:

char string[] = "hello world"; 
char *result = strtok(string, " "); 

Questo causa un errore di segmentazione:

char *string = "hello world"; 
char *result = strtok(string, " "); 

Qualcuno può spiegare che cosa provoca questa differenza di comportamento?

risposta

23
char string[] = "hello world"; 

Questa linea inizializza string ad essere un grande abbastanza serie di personaggi (in questo caso char[12]). Si copia quei personaggi nel tuo matrice locale come se fosse stato scritto fuori

char string[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0' }; 

L'altra linea:

char* string = "hello world"; 

non inizializza una matrice locale, semplicemente inizializza un puntatore locale. Il compilatore è permesso di impostarlo su un puntatore ad un array che non ti è permesso di cambiare, come se il codice fosse

const char literal_string[] = "hello world"; 
char* string = (char*) literal_string; 

Il motivo C permette questo senza un cast è principalmente quello di lasciare che il codice antica continua la compilazione. Dovresti far finta che il tipo di stringa letterale nel codice sorgente sia const char[], che può essere convertito in const char*, ma non convertirlo mai in un char*.

+0

Molte buone risposte, ma ho trovato questo l'esempio più chiaro del problema fondamentale. –

+0

+1 spiegazione eccellente –

10

Nel secondo esempio:

char *string = "hello world"; 
char *result = strtok(string, " "); 

il puntatore string sta indicando una stringa letterale, che non può essere modificato (come strtok() vorrebbe fare).

si potrebbe fare qualcosa sulla falsariga di:

char *string = strdup("hello world"); 
char *result = strtok(string, " "); 

in modo che string sta puntando a una copia modificabile del letterale.

+0

Ho intenzione di resistere all'impulso di -1, ma davvero non mi piace questa risposta. Penso che porti i newbie coder all'idioma di buttare in giro 'strdup' per risolvere i segoult invece di imparare come gestire la memoria (e in particolare le stringhe). Ma non sono sicuro di quale sarebbe una risposta migliore senza dire "basta usare l'array o allocare dinamicamente la memoria per la stringa". A proposito, 'strdup' non è C standard, ma ovviamente è abbastanza facile implementarlo su sistemi che non ce l'hanno. –

0

Il primo caso crea un array di caratteri (non const) grande abbastanza da contenere la stringa e inizializzarla con il contenuto della stringa. Il secondo caso crea un puntatore char e lo inizializza per puntare al letterale stringa, che è probabilmente memorizzato nella memoria di sola lettura.

Poiché strtok vuole modificare la memoria puntata dall'argomento lo si passa, il secondo caso causa un comportamento non definito (si passa a un puntatore che punta a un valore letterale di stringa (const)), quindi è insuperabile che esso arresti anomali

3

Nel secondo caso (char *), la stringa è in memoria di sola lettura. Il corretto tipo di costanti stringa è const char * e, se si è utilizzato quel tipo per dichiarare la variabile, il compilatore verrà avvisato quando si tenta di modificarlo. Per ragioni storiche, puoi utilizzare le costanti stringa per inizializzare le variabili di tipo char * anche se non possono essere modificate. (Alcuni compilatori consentono di attivare questa licenza storica via, ad esempio con gcc di -Wwrite-strings.)

+0

Vale anche la pena ricordare che, nel primo caso, c'è una copia implicita della stringa letterale nel char array. Ecco perché non hai lo stesso problema. –

+0

'const char *' produce anche un segfault se si tenta di essere usato con 'strtok', ma almeno fornisce un avviso di compilazione. Ma noto che la modifica è il problema. –

+0

Sì, avrei dovuto essere meno telegrafico. Risposta modificata. – zwol

0

Perché il secondo dichiara un puntatore (che può cambiare) per una stringa costante ...

Quindi, a seconda del compilatore/piattaforma/OS/mappa di memoria ... la stringa "ciao mondo" verrà memorizzata come costante (in un sistema incorporato, può essere memorizzata nella ROM) e provare a modificarlo causerà quell'errore.

4

strtok modifica la stringa passata (o tenta comunque). Nel tuo primo codice, stai passando l'indirizzo di un array che è stato inizializzato su un valore particolare, ma poiché è un normale array di caratteri, è consentita la modifica.

Nel secondo codice, si passa l'indirizzo di una stringa letterale.Il tentativo di modificare una stringa letterale dà un comportamento indefinito.

Problemi correlati