Per quanto adoro il C e il C ++, non posso fare a meno di grattarmi la testa nella scelta di stringhe con terminazione null:
- Le stringhe con prefisso di lunghezza (cioè Pascal) esistevano prima di C
- Le stringhe con prefisso di lunghezza rendono più veloci diversi algoritmi consentendo una ricerca della lunghezza temporale costante.
- Le stringhe con prefisso di lunghezza rendono più difficile causare errori di sovraccarico del buffer.
- Anche su una macchina a 32 bit, se si consente alla stringa di avere la dimensione della memoria disponibile, una stringa con prefisso di lunghezza è solo tre byte più larga di una stringa con terminazione nulla. Su macchine a 16 bit questo è un singolo byte. Su macchine a 64 bit, 4 GB è un limite di lunghezza della stringa ragionevole, ma anche se si desidera espanderlo alla dimensione della parola macchina, le macchine a 64 bit di solito hanno una memoria ampia che rende i sette byte extra una sorta di argomento null. So che lo standard C originale è stato scritto per macchine follemente povere (in termini di memoria), ma l'argomento dell'efficienza non mi vende qui.
- Praticamente ogni altra lingua (ad es. Perl, Pascal, Python, Java, C #, ecc.) Usa stringhe con prefisso di lunghezza. Queste lingue di solito battono C nei benchmark di manipolazione delle stringhe perché sono più efficienti con le stringhe.
- Il C ++ ha corretto un po 'questo con il
std::basic_string
modello, ma le matrici di caratteri semplici che prevedono stringhe con terminazione null sono ancora pervasive. Anche questo è imperfetto perché richiede l'allocazione dell'heap. - Le stringhe con terminazione nulla devono riservare un carattere (vale a dire null), che non può esistere nella stringa, mentre le stringhe con prefisso di lunghezza possono contenere null incorporati.
Molte di queste cose sono venute alla luce più recentemente di C, quindi avrebbe senso che C non le conoscesse. Tuttavia, molti erano chiaramente ben prima che C diventasse. Perché sarebbero state scelte le stringhe nulle invece del prefisso ovviamente di lunghezza superiore?
EDIT : Poiché alcuni hanno chiesto fatti (e non mi sono piaciuti quelli che ho già fornito) sul mio punto di efficienza sopra, derivano da alcune cose:
- Concat utilizzando stringhe con terminazione null richiede O (n + m) complessità temporale. Il prefisso di lunghezza richiede spesso solo O (m).
- La lunghezza usando stringhe con terminazione null richiede O (n) complessità temporale. Il prefisso di lunghezza è O (1).
- La lunghezza e il concat sono le operazioni di stringa di gran lunga più comuni. Esistono diversi casi in cui le stringhe con terminazione null possono essere più efficienti, ma si verificano molto meno spesso.
Dalle risposte di seguito, questi sono alcuni casi in cui le stringhe con terminazione null sono più efficienti:
- Quando è necessario tagliare l'inizio di una stringa e passarlo a un metodo. Non puoi davvero farlo in tempo costante con il prefisso di lunghezza anche se ti è permesso distruggere la stringa originale, perché probabilmente il prefisso di lunghezza deve seguire le regole di allineamento.
- In alcuni casi in cui stai semplicemente eseguendo il looping della stringa carattere per carattere, potresti essere in grado di salvare un registro CPU. Nota che questo funziona solo nel caso in cui non hai allocato dinamicamente la stringa (Perché allora dovresti liberarla, necessitando di usare quel registro CPU che hai salvato per contenere il puntatore che originariamente avevi da malloc e dagli amici).
Nessuna delle precedenti è quasi comune quanto la lunghezza e il concat.
Ce n'è un altro affermato nelle risposte di seguito:
- Devi tagliare l'estremità della stringa
ma questo non è corretto - è la stessa quantità di tempo per stringhe con terminazione null e lunghezza prefissata. (Le stringhe con terminazione Null si limitano a incollare un valore nullo nel punto in cui si desidera che si trovi la nuova estremità, i prefissi di lunghezza vengono sottratti dal prefisso.)