Саме так це звучить, якщо припустити, що ви звикли до скороченого способу, коли C і UNIX призначає слова, він дублює рядки :-)
Маючи на увазі, що насправді не є частиною самого стандарту ISO C (а) (це POSIX), він фактично робить те саме, що і наступний код:
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
}
Іншими словами:
Він намагається виділити достатню кількість пам'яті, щоб вмістити стару рядок (плюс символ \ \ 0 ', щоб позначити кінець рядка).
Якщо розподіл не вдалося, він встановлює errnoв ENOMEMі повертається NULLвідразу. Налаштування errnoдо ENOMEM- це щось mallocв POSIX, тому нам не потрібно прямо робити це в нашому strdup. Якщо ви не сумісні з POSIX, ISO C насправді не вимагає існування, ENOMEMтому я тут не включив це (b) .
Інакше розподіл спрацювало, тому ми копіюємо стару рядок у нову рядок (c) і повертаємо нову адресу (за що абонент відповідає за звільнення в якийсь момент).
Майте на увазі, що це концептуальне визначення. Будь-який автор бібліотеки, який вартує своєї зарплати, може надати сильно оптимізований код, орієнтований на конкретний процесор, який використовується.
(a) Однак функції, що починаються з strмалої літери, зарезервовані стандартом для майбутніх напрямків. Від C11 7.1.3 Reserved identifiers:
Кожен заголовок декларує або визначає всі ідентифікатори, перелічені в його асоційованому підпункті, і * необов'язково декларує або визначає ідентифікатори, перелічені у відповідному підпункті майбутніх напрямків бібліотеки. **
Майбутні вказівки string.hможна знайти у C11 7.31.13 String handling <string.h>:
Імена функцій, які починаються з str, memабо wcsі малої літери можуть бути додані до декларацій у <string.h>заголовку.
Тож вам, мабуть, слід назвати це ще чимось, якщо ви хочете бути в безпеці.
(b) Зміна в основному буде замінювати if (d == NULL) return NULL;:
if (d == NULL) {
errno = ENOMEM;
return NULL;
}
(c) Зауважте, що я використовую strcpyдля цього, оскільки це чітко показує наміри. У деяких реалізаціях використовувати їх можна швидше (оскільки ви вже знаєте довжину) memcpy, оскільки вони можуть дозволяти переносити дані більш великими фрагментами, або паралельно. А може і не :-) Мантра оптимізації №1: "міряй, не здогадуйся".
У будь-якому випадку, якщо ви вирішили пройти цей маршрут, ви зробите щось на кшталт:
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
}