strdup() - ¿Qué hace en C?
¿ Cuál es el propósito de la strdup()
función en C?
Exactamente lo que parece, suponiendo que esté acostumbrado a la forma abreviada en la que C y UNIX asignan palabras, duplica cadenas :-)
Teniendo en cuenta que en realidad no es parte del estándar ISO C actual (C17) (a) (es una cosa POSIX), efectivamente hace 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 antigua (más un carácter '\0' para marcar el final de la cadena).
Si la asignación falla, se establece
errno
yENOMEM
regresaNULL
inmediatamente. La configuración deerrno
toENOMEM
es algomalloc
que se hace en POSIX, por lo que no es necesario hacerlo explícitamente en nuestro archivostrdup
. Si no es compatible con POSIX, ISO C en realidad no exige la existencia deENOMEM
, por lo que no lo 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 bibliotecas que valga su salario puede haber proporcionado un código muy optimizado dirigido al procesador particular que se utiliza.
Otra cosa a tener en cuenta es que parece que actualmente está programado para estar en la iteración C2x del estándar, junto con strndup
, según el borrador N2912
del documento.
(a) Sin embargo, las funciones que comienzan con str
una letra minúscula están reservadas por la norma para instrucciones futuras. 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 identificadores enumerados en su subcláusula asociada de direcciones de biblioteca futuras. *
Las instrucciones futuras se string.h
pueden encontrar en C11 7.31.13 String handling <string.h>
:
Los nombres de funciones que comienzan con
str
,mem
owcs
y una letra minúscula se pueden agregar a las declaraciones en el<string.h>
encabezado.
Así que probablemente deberías llamarlo de otra manera si quieres estar seguro.
(b) El cambio básicamente sería reemplazar 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 muestra claramente la intención. En algunas implementaciones, puede ser más rápido (dado que ya conoce la longitud) utilizar memcpy
, ya que pueden permitir transferir los datos en fragmentos más grandes o en paralelo. O puede que no :-) Mantra de optimización n.º 1: "mide, no adivines".
En cualquier caso, si decide seguir ese camino, 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
}
char * strdup(const char * s)
{
size_t len = 1+strlen(s);
char *p = malloc(len);
return p ? memcpy(p, s, len) : NULL;
}
Tal vez el código sea un poco más rápido que con, ya que no es necesario volver a buscar strcpy()
el carácter (ya lo era con ).\0
strlen()
No tiene sentido repetir las otras respuestas, pero tenga en cuenta que strdup()
puede hacer lo que quiera desde una perspectiva de C, ya que no forma parte de ningún estándar de C. Sin embargo, está definido por POSIX.1-2001.
Del hombre strdup :
La strdup()
función devolverá un puntero a una nueva cadena, que es un duplicado de la cadena a la que apunta s1
. El puntero devuelto se puede pasar a free()
. Se devuelve un puntero nulo si no se puede crear la nueva cadena.
strdup() realiza una asignación de memoria dinámica para la matriz de caracteres, incluido el carácter final '\0' y devuelve la dirección de la memoria del montón:
char *strdup (const char *s)
{
char *p = malloc (strlen (s) + 1); // allocate memory
if (p != NULL)
strcpy (p,s); // copy string
return p; // return the memory
}
Entonces, lo que hace es darnos otra cadena idéntica a la cadena dada por su argumento, sin requerir que le asignemos memoria. Pero aún necesitamos liberarlo más tarde.