Esattamente come sembra, supponendo che tu sia abituato al modo abbreviato in cui C e UNIX assegnano le parole, duplica le stringhe :-)
Tenendo presente che in realtà non fa parte dello standard ISO C stesso (a) (è una cosa POSIX), sta effettivamente facendo lo stesso del seguente codice:
char *strdup(const char *src) {
char *dst = malloc(strlen (src) + 1); // Space for length plus nul
if (dst == NULL) return NULL; // No memory
strcpy(dst, src); // Copy the characters
return dst; // Return the new string
}
In altre parole:
Tenta di allocare memoria sufficiente per contenere la vecchia stringa (più un carattere '\ 0' per segnare la fine della stringa).
Se l'assegnazione non è riuscita, imposta errno
per ENOMEM
e ritorna NULL
immediatamente. L'impostazione di errno
to ENOMEM
è qualcosa che malloc
fa in POSIX, quindi non è necessario farlo esplicitamente nel nostro strdup
. Se sei non conforme a POSIX, ISO C in realtà non mandato l'esistenza di ENOMEM
così non ho incluso che qui (b) .
Altrimenti l'allocazione ha funzionato, quindi copiamo la vecchia stringa nella nuova stringa (c) e restituiamo il nuovo indirizzo (che il chiamante è responsabile della liberazione a un certo punto).
Tieni presente che è la definizione concettuale. Qualsiasi scrittore degno del proprio stipendio può aver fornito un codice fortemente ottimizzato destinato al particolare processore utilizzato.
(a) Tuttavia, le funzioni che iniziano con str
e una lettera minuscola sono riservate dallo standard per le direzioni future. Da C11 7.1.3 Reserved identifiers
:
Ogni intestazione dichiara o definisce tutti gli identificatori elencati nella sua sotto-clausola associata e * facoltativamente dichiara o definisce gli identificatori elencati nella sua sotto-clausola delle direzioni della libreria future associate. **
Le direzioni future per string.h
possono essere trovate in C11 7.31.13 String handling <string.h>
:
I nomi delle funzioni che iniziano con str
, mem
o wcs
e una lettera minuscola possono essere aggiunti alle dichiarazioni del <string.h>
intestazione.
Quindi dovresti probabilmente chiamarlo qualcos'altro se vuoi essere al sicuro.
(b) La modifica verrebbe sostanzialmente sostituita if (d == NULL) return NULL;
da:
if (d == NULL) {
errno = ENOMEM;
return NULL;
}
(c) Nota che lo uso strcpy
per quello poiché questo mostra chiaramente l'intento. In alcune implementazioni, può essere più veloce (poiché si conosce già la lunghezza) da utilizzare memcpy
, in quanto possono consentire il trasferimento dei dati in blocchi più grandi o in parallelo. Oppure potrebbe non :-) Mantra di ottimizzazione # 1: "misura, non indovinare".
In ogni caso, se decidessi di percorrere quella strada, faresti qualcosa del tipo:
char *strdup(const char *src) {
size_t len = strlen(src) + 1; // String plus '\0'
char *dst = malloc(len); // Allocate space
if (dst == NULL) return NULL; // No memory
memcpy (dst, src, len); // Copy the block
return dst; // Return the new string
}