2010-04-23 13 views
5

Sono venuto a disturbare tutti con un'altra domanda C probabilmente molto semplice.Quick strlen question

utilizzando il seguente codice:

int get_len(char *string){ 

    printf("len: %lu\n", strlen(string)); 

    return 0; 
} 

int main(){ 

    char *x = "test"; 
    char y[4] = {'t','e','s','t'}; 

    get_len(x); // len: 4 
    get_len(y); // len: 6 

    return 0; 
} 

2 domande. Perché sono diversi e perché è 6? Grazie ragazzi.

EDIT: Scusa, so cosa aggiustarlo, volevo solo capire cosa stava succedendo. Quindi strlen continua a inoltrare il punto fino a quando non trova un \ 0? Anche quando ho eseguito il comando nella funzione principale invece che nella funzione get_len, entrambi erano 4. Era solo una coincidenza?

+0

Sì, è stata solo una coincidenza. – AnT

+0

A parte le risposte (che sono eccellenti se un po 'ripetitive) vorrei sottolineare che mentre "test" è una comoda sintassi per la sequenza "t", "e", "s", "t" , 0', puoi infatti come caso speciale inizializzare un array di caratteri con 'char y [4] =" test ";' nel qual caso verrà omesso lo 0 finale (non c'è semplicemente spazio per esso in 'y'). –

risposta

13

non è terminato con null. strlen() conta i caratteri finché non raggiunge un carattere null. Il tuo è successo a trovarne uno dopo il 6, ma potrebbe essere un qualsiasi numero. Prova questo:

char y[] = {'t','e','s','t', '\0'};

Ecco cosa un'implementazione di strlen() potrebbe assomigliare (la parte superiore della mia testa - non hanno il mio K & R libro a portata di mano, ma credo che ci sia un'implementazione dato lì) :

size_t strlen(const char* s) 
{ 
    size_t result = 0; 
    while (*s++) ++result; 
    return result; 
} 
+0

Quindi è solo necessario inoltrare il puntatore fino a quando non trova qualche \ 0 dove può? – LearningC

+1

@LearningC: esattamente. Continua a incrementare il puntatore e guarda cosa c'è. Quando trova uno zero, si ferma e restituisce quanti caratteri ha guardato (escluso lo zero). –

+4

@LearningC: Sì. O fino a quando non si blocca con un segfault. O finché non formatta il tuo disco rigido. Il comportamento è * non definito * se il tuo input non è a terminazione zero. *Tutto può succedere. – AnT

2

È necessario annullare l'operazione y.

int get_len(char *string){ 

    printf("len: %lu\n", strlen(string)); 

    return 0; 
} 

int main(){ 

    char *x = "test"; 
    char y[5] = {'t','e','s','t','\0'}; 

    get_len(x); // len: 4 
    get_len(y); // len: 4 

    return 0; 
} 

strlen() prende in pratica il puntatore si dà e conta il numero di byte fino alla prossima NULL in memoria. E 'successo che ci fosse un NULL a due byte più tardi nella tua memoria.

+0

Quindi è necessario solo inoltrare il puntatore fino a quando non trova qualche \ 0 dove può? – LearningC

+0

Due problemi con questo. Primo, NULL è inteso come un puntatore nullo, non un carattere nullo. Secondo, hai ancora 'char y [4]', quindi hai un inizializzatore extra. Hai bisogno di cinque posizioni per avere una stringa "test". –

+0

@LearningC: In una parola, sì. Questa è una buona descrizione. –

4

Questo

char y[4] = {'t','e','s','t'}; 

non è una corretta terminata da zero s tring. È una serie di quattro caratteri, senza il '\0' terminante. strlen() conta semplicemente i caratteri finché non raggiunge lo zero. Con y conta semplicemente oltre la fine dell'array finché non trova accidentalmente un byte zero.
In questo modo si sta invocando un comportamento non definito. Il codice potrebbe anche formattare il tuo disco rigido.

È possibile evitare questo utilizzando la sintassi speciale per l'inizializzazione array di caratteri:

char y[] = "test"; 

Questo inizializza y con cinque personaggi, dal momento che aggiunge automaticamente un '\0'.
Nota che ho anche lasciato le dimensioni dell'array non specificato. Il compilatore lo calcola da solo, e automaticamente ridimensiona se cambio la lunghezza della stringa.

proposito, ecco una semplice applicazione strlen():

size_t strlen(const char* p) 
{ 
    size_t result = 0; 
    while(*p++) ++result; 
    return result; 
} 

implementazioni moderni probabilmente non prendere singoli byte o anche utilizzare intrinseci della CPU, ma questo è l'algoritmo di base.

+0

Wow, non ho visto il tuo 'strlen()' prima di aggiungere il mio. Sono identici! Grandi menti ... 8v) –

+0

La sorgente GNU libc per le funzioni di stringa è abbastanza illuminante da attirare l'attenzione e sorprendentemente complessa. –

+0

@Fred: Beh, è ​​uno degli algoritmi più fondamentali della libreria C ed è un ottimo esempio in K & R. Non c'è da stupirsi che la maggior parte di noi lo abbia impresso nella loro memoria. – sbi

3

che segue non è un nullo terminata array di caratteri:

char y[4] = {'t','e','s','t'}; 

Parte del contratto strlen() s' è che sia dotata di un puntatore a una stringa terminata nullo. Dal momento che ciò non accade con strlen(y), si ottiene un comportamento non definito. Nel tuo caso specifico, viene restituito 6, ma può accadere di tutto, incluso un arresto anomalo del programma.

Da 7.1.1 "Definizione dei termini" di C99:

Un stringa è una sequenza contigua di caratteri terminati da e comprendente il primo carattere nullo .

0
char y[5] = {'t','e','s','t','\0'}; 

sarebbe lo stesso di

char *x = "test"; 
+1

Ai fini di 'strlen()', sì. Tuttavia, 'y' è un array di cinque' char', e il suo contenuto può essere modificato a piacimento. 'x' è un puntatore a' char', e in questo caso punta a una stringa che non può essere modificata in modo affidabile. D'altra parte, è possibile riassegnare un valore a 'x' ma non a' y'. –

+0

@David Thornley la risposta è stata data in un contesto principiante solo per illustrare cosa è andato storto secondo l'OP. Ora venivano date risposte migliori. Non c'è bisogno di downvotare – stacker

+0

IME esattamente le differenze così sottili come questo ('x [0] = 'x';' va bene quando hai detto 'char x [] =" X ";', ma fatale quando dici 'char * x = "X"; ') non può mai essere stressato troppo, specialmente per i principianti. – sbi

3

strlen opere con stringhe. La stringa è definita come una sequenza (matrice) di caratteri terminata con il carattere \0.

I tuoi x indicano una stringa. Così, strlen funziona bene con x come argomento.

Il tuo non è una stringa. Per questo motivo, passando y a strlen risultati in un comportamento indefinito. Il risultato è privo di significato e imprevedibile.

1

Una stringa di tipo C effettiva è più grande del numero dei suoi caratteri, poiché ha bisogno di un carattere nullo di fine.

Pertanto, char y[4] = {'t','e','s','t'}; non forma una stringa, poiché è composta da quattro caratteri. char y[] = "test"; o char y[5] = "test"; formerebbero una stringa, da quando erano hanno un array di caratteri di cinque caratteri che terminano con il terminatore null-byte.

0

Come altri hanno già detto, è necessario assicurarsi di terminare una stringa con il carattere 0 o '\ 0'. Come nota a margine, puoi verificarlo: http://bstring.sourceforge.net/. Ha una funzione di lunghezza della stringa O (1), a differenza dello strlen C/C++ che è soggetto a errori e lento a O (N), dove N è il numero di caratteri non nulli. Non ricordo l'ultima volta in cui ho usato strlen e sono amici. Vai al sicuro & veloce funzioni/classi!