Exactamente cómo suena, suponiendo que esté acostumbrado a la forma abreviada en que C y UNIX asignan palabras, duplica las cadenas :-)
Teniendo en cuenta que en realidad no es parte del estándar ISO C en sí (a) (es una cosa POSIX), efectivamente está haciendo lo mismo que el siguiente código:
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
}
En otras palabras:
Intenta asignar suficiente memoria para contener la cadena anterior (más un carácter '\ 0' para marcar el final de la cadena).
Si la asignación no, se establece errno
para ENOMEM
y vuelve NULL
inmediatamente. La configuración de errno
to ENOMEM
es algo que malloc
hace en POSIX, por lo que no necesitamos hacerlo explícitamente en nuestro strdup
. Si no cumple con POSIX, ISO C en realidad no exige la existencia de ENOMEM
lo que no he incluido aquí (b) .
De lo contrario, la asignación funcionó, por lo que copiamos la cadena anterior a la nueva cadena (c) y devolvemos la nueva dirección (que la persona que llama es responsable de liberar en algún momento).
Tenga en cuenta que esa es la definición conceptual. Cualquier escritor de biblioteca que valga su salario puede haber proporcionado un código altamente optimizado dirigido al procesador particular que se está utilizando.
(a) Sin embargo, las funciones que comienzan con str
una letra minúscula están reservadas por el estándar para futuras instrucciones. De C11 7.1.3 Reserved identifiers
:
Cada encabezado declara o define todos los identificadores enumerados en su subcláusula asociada, y * opcionalmente declara o define los identificadores enumerados en su subcláusula de direcciones de biblioteca futura asociada. **
Las direcciones futuras para string.h
se pueden encontrar en C11 7.31.13 String handling <string.h>
:
Los nombres de funciones que comienzan con str
, mem
o wcs
y una letra minúscula se pueden agregar a las declaraciones en el <string.h>
encabezado.
Por lo tanto, probablemente debería llamarlo de otra manera si desea estar seguro.
(b) El cambio básicamente se reemplazaría if (d == NULL) return NULL;
con:
if (d == NULL) {
errno = ENOMEM;
return NULL;
}
(c) Tenga en cuenta que lo uso strcpy
para eso, ya que eso muestra claramente la intención. En algunas implementaciones, puede ser más rápido (ya que ya conoce la longitud) de usar memcpy
, ya que pueden permitir la transferencia de datos en fragmentos más grandes o en paralelo. O puede que no :-) Mantra de optimización # 1: "medir, no adivinar".
En cualquier caso, si decide ir por esa ruta, haría algo como:
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
}