2010-04-19 8 views
11

Sto entrando in C/C++ e un sacco di termini stanno spuntando non mi è familiare. Uno di questi è una variabile o un puntatore che termina con uno zero. Cosa significa che uno spazio nella memoria deve essere terminato da uno zero?Cosa significa essere "terminato da uno zero"?

+6

Questa frase termina con un punto. Quindi è questo. MA NON QUESTO! – polygenelubricants

+2

Joel ha un bell'articolo su questo (e cose correlate): http://www.joelonsoftware.com/articles/fog0000000319.html – NomeN

risposta

16

Prendere la stringa Hi in ASCII. La sua rappresentazione più semplice in memoria è di due byte:

0x48 
0x69 

Ma da dove viene quel pezzo di memoria finisce? A meno che tu non sia disposto a passare il numero di byte nella stringa, non lo sai - i pezzi di memoria non hanno intrinsecamente una lunghezza.

Quindi C ha uno standard che le stringhe terminano con un byte zero, noto anche come un personaggio NUL:

0x48 
0x69 
0x00 

La stringa è ora privo di ambiguità le due caratteri, perché ci sono due personaggi prima della NUL.

+1

Gli overflow del buffer si verificano quando non ci si rende conto che sono necessari tre byte per memorizzare due caratteri. – MSalters

+1

@MSalters: No, accadono quando capisci che una stringa di lunghezza due è composta da tre caratteri. :-) –

14

E 'un valore riservato per indicare la fine di una sequenza di caratteri (ad esempio) in una stringa.

Più correttamente noto come null (or NUL) terminated. Questo perché il valore utilizzato è zero, piuttosto che essere il codice carattere per '0'. Per chiarire la distinzione controlla una tabella di ASCII character set.

Ciò è necessario perché le lingue come C hanno un tipo di dati char, ma non il tipo di dati string. Pertanto è lasciato al devleoper decidere come gestire le stringhe nella loro applicazione. Il solito modo di fare ciò è di avere un array di char s con un valore nullo usato per terminare (cioè significare la fine della) stringa.

Si noti che esiste una distinzione tra la lunghezza della stringa e la lunghezza del char array originariamente dichiarato.

char name[50]; 

Questo dichiara una matrice di 50 caratteri. Tuttavia, questi valori non saranno inizializzati. Quindi, se voglio memorizzare la stringa "Hello" (5 caratteri), non voglio preoccuparmi di impostare i restanti 45 caratteri in spazi (o qualche altro valore). Invece memorizzo un valore NUL dopo l'ultimo carattere nella mia stringa.

Più lingue recenti come Pascal, Java e C# hanno un tipo specifico string definito. Questi hanno un valore di intestazione per indicare il numero di caratteri nella stringa. Questo ha un paio di vantaggi; in primo luogo non è necessario camminare fino alla fine della stringa per scoprire la sua lunghezza, in secondo luogo la stringa può contain null characters.

Wikipedia ha ulteriori informazioni nella voce String (computer science).

+0

Re: lingue più recenti: IIRC, che si chiama una stringa Pascal – Hasturkun

+0

stringhe Pascal specificamente utilizzato un singolo byte per contenere la lunghezza della stringa. Come puoi facilmente intuire, non è abbastanza! I moderni tipi 'stringa' probabilmente usano invece' size_t'; se la tua stringa non si adatta a questo, la stringa non sarà tenuta interamente in memoria. –

0

Gli array e la stringa in C sono solo indicatori di una posizione di memoria. Per puntatore puoi trovare un inizio di array. La fine della matrice non è definita. La fine dell'array di caratteri (che è la stringa) è zero byte.

Così, in memoria ciao stringa viene scritto come:

68 65 6c 6c 6f 00         |hello| 
0

Si riferisce al modo in cui le stringhe C sono memorizzati nella memoria. Il carattere NUL rappresentato da \ 0 nelle stringhe iterali è presente alla fine di una stringa C in memoria. Ad esempio, non vi sono altri metadati associati ad una lunghezza di tipo C come la lunghezza. Notare la diversa ortografia tra il carattere NUL e il puntatore NULL.

0

Le stringhe in stile C sono terminate da un carattere NUL ('\ 0'). Questo fornisce un marker per le funzioni che operano su stringhe (ad es. Strlen, strcpy) da utilizzare per identificare la fine della stringa.

4

denuncia da parte di uno zero

E 'quando il tuo capo a punta con i capelli si spara.

0

Esistono due metodi comuni per gestire gli array che possono avere contenuti di lunghezza variabile (come le stringhe). Il primo è quello di mantenere separatamente la lunghezza dei dati memorizzati nell'array. Lingue come Fortran e Ada e C++ std :: string fai questo. Lo svantaggio di fare questo è che in qualche modo devi passare quell'informazione in più a tutto ciò che ha a che fare con il tuo array.

L'altro modo consiste nel riservare un elemento extra non dati alla fine dell'array per fungere da sentinella. Per la sentinella si utilizza un valore che non dovrebbe mai apparire nei dati reali. Per le stringhe, 0 (o "NUL") è una buona scelta, poiché non è stampabile e non serve ad altri scopi in ASCII. Quindi, ciò che C (e molte lingue copiate da C) fanno è assumere che tutte le stringhe finiscano (o "siano terminate da") a 0.

Ci sono diversi inconvenienti a questo. Per prima cosa, è lento. Ogni volta che una routine ha bisogno di conoscere la lunghezza della stringa, è un'operazione di tipo O (n) (cercando l'intera stringa cercando lo 0). Un altro problema è che un giorno potresti voler inserire uno 0 nella stringa per qualche motivo, quindi ora hai bisogno di un intero secondo set di routine di stringhe che ignorino il null e utilizzino comunque una lunghezza separata (ad esempio: strnlen()). Il terzo grosso problema è che se qualcuno dimentica di mettere quello 0 alla fine (o viene spazzato via in qualche modo), la prossima operazione di stringa per fare un ultimo controllo andrà allegramente attraverso la memoria fino a quando non capita di trovare casualmente un altro 0, si blocca, o l'utente perde la pazienza e lo uccide. Tali bug possono essere una PITA seria da rintracciare.

Per tutti questi motivi, l'approccio C è generalmente considerato sfavorevole.

0

Mentre il classico esempio di "terminato da uno zero" è quello delle stringhe in C, il concetto è più generale. Può essere applicato a qualsiasi elenco di elementi memorizzati in un array, la cui dimensione non è nota esplicitamente.

Il trucco è semplicemente quello di evitare di passare attorno a una dimensione di un array aggiungendo un valore sentinella alla fine dell'array. In genere, viene utilizzata una forma di zero, ma può essere qualsiasi altra cosa (come un NAN se la matrice contiene valori in virgola mobile).

Ecco tre esempi di questo concetto: le stringhe

  1. C, naturalmente. Un carattere zero singolo viene aggiunto alla stringa: "Hello" è codificato come 48 65 6c 6c 6f 00.

  2. Le matrici di puntatori consentono naturalmente la terminazione zero, poiché il puntatore nullo (quello che punta all'indirizzo zero) è definito per non puntare mai a un oggetto valido.Come tale, si potrebbe trovare il codice come questo:

    Foo list[] = { somePointer, anotherPointer, NULL }; 
    bar(list); 
    

    invece di

    Foo list[] = { somePointer, anotherPointer }; 
    bar(sizeof(list)/sizeof(*list), list); 
    

    Questo è il motivo per cui l'execvpe() ha bisogno solo tre argomenti, due dei quali passano le matrici di definito dall'utente lunghezza. Dal momento che tutto ciò che è passato a sono (probabilmente molte) stringhe, questa piccola funzione mette in mostra due livelli di terminazione zero: puntatori nulli che terminano gli elenchi di stringhe e caratteri null che terminano le stringhe stesse.

  3. Anche se il tipo di elemento dell'array è un più complesso struct, può ancora essere terminato con zero. In molti casi, uno dei membri struct è definito come quello che segnala la fine dell'elenco. Ho visto tali definizioni di funzioni, ma non riesco a scoprire un buon esempio di questo in questo momento, mi dispiace. In ogni caso, il codice chiamante sarebbe simile a questa:

    Foo list[] = { 
        { someValue, somePointer }, 
        { anotherValue, anotherPointer }, 
        { 0, NULL } 
    }; 
    bar(list); 
    

    o anche

    Foo list[] = { 
        { someValue, somePointer }, 
        { anotherValue, anotherPointer }, 
        {} //C zeros out an object initialized with an empty initializer list. 
    }; 
    bar(list); 
    
Problemi correlati