Какова цель функции strdup()
в C?
Точно, как это звучит, предполагая, что вы привыкли к сокращенному пути, в котором C и UNIX присваивают слова, он дублирует строки :-)
Имея в виду, что это фактически не является частью стандарта ISO C (a) (это вещь POSIX), он эффективно выполняет те же действия, что и следующий код:
char *strdup (const char *s) {
char *d = malloc (strlen (s) + 1); // Space for length plus nul
if (d == NULL) return NULL; // No memory
strcpy (d,s); // Copy the characters
return d; // Return the new string
}
Другими словами:
Он пытается выделить достаточно памяти для хранения старой строки (плюс символ "\ 0", чтобы отметить конец строки).
Если распределение не удалось, оно устанавливает errno
в ENOMEM
и немедленно возвращает NULL
. Установка errno
в ENOMEM
- это что-то, что malloc
делает в POSIX, поэтому нам не нужно явно делать это в нашей strdup
. Если вы не совместимы с POSIX, ISO C на самом деле не гарантирует существование ENOMEM
поэтому я не включил здесь (b).
В противном случае распределение работало, поэтому мы копируем старую строку в новую строку и возвращаем новый адрес (на который вызывающий абонент отвечает за освобождение в какой-то момент).
Имейте в виду, что концептуальное определение. Любой архитектор библиотеки, заслуживающий своей зарплаты, может предоставить сильно оптимизированный код, предназначенный для конкретного используемого процессора.
(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;
}
char * strdup(const char * s)
{
size_t len = 1+strlen(s);
char *p = malloc(len);
return p ? memcpy(p, s, len) : NULL;
}
Возможно, код немного быстрее, чем с strcpy()
, поскольку \0
char не нужно искать снова (он уже был с strlen()
).
return memcpy(malloc(len), s, len);
как я предпочитаю сбой при распределении, а не NULL
при сбое выделения.
NULL
не должно произойти сбой; это не определено Если вы хотите быть уверенным, что он выйдет из строя, напишите emalloc
который вызывает abort
при emalloc
.
Нет смысла повторять другие ответы, но учтите, что strdup()
может делать все, что захочет, с точки зрения C, так как не является частью какого-либо стандарта C. Однако он определяется POSIX.1-2001.
strdup()
переносимым? Нет, недоступно в среде, отличной от POSIX (в любом случае, легко реализуемо). Но сказать, что функция POSIX может делать что угодно, довольно педантично. POSIX - это еще один стандарт, который так же хорош, как C, и еще более популярен.
strdup
в качестве расширения. В такой реализации нет гарантии, что strdup
ведет себя так же, как функция POSIX. Я не знаю ни одной такой реализации, но законная не злонамеренная реализация может предоставить char *strdup(char *)
по историческим причинам и отклонить попытки передать const char *
.
Из strdup man:
Функция strdup()
должна возвращать указатель на новую строку, которая является дубликатом строки, на которую указывает s1
. Возвращаемый указатель можно передать в free()
. Возвращает нулевой указатель, если новая строка не может быть создана.
strdup() выполняет динамическое выделение памяти для массива символов, включая конечный символ '\ 0', и возвращает адрес памяти кучи:
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
}
Итак, что он делает, это дать нам еще одну строку, идентичную строке, заданной его аргументом, без необходимости выделять память. Но нам еще нужно освободить его позже.
Он создает дублируемую копию строки, переданной с помощью malloc и strcpy строки, переданной в. Буфер malloc'ed возвращается вызывающему, следовательно, необходимо запустить бесплатно по возвращаемому значению.
strdup
и strndup
определены в POSIX-совместимых системах как:
char *strdup(const char *str);
char *strndup(const char *str, size_t len);
Функция strdup() выделяет достаточную память для копии строки str
, делает копию и возвращает указатель на нее.
Указатель впоследствии может быть использован как аргумент функции free
.
Если доступно недостаточное количество памяти, возвращается NULL
а errno
- в ENOMEM
.
Функция strndup() копирует не более len
символов из строки str
всегда нулевая, заканчивая скопированную строку.
Функция strdup() является сокращением для строкового дубликата, она принимает параметр как строчную константу или строковый литерал и выделяет достаточно места для строки и записывает соответствующие символы в выделенном пространстве и, наконец, возвращает адрес от выделенного пространства к вызывающей процедуре.
strdup
не обязательно должен быть строковой константой, он должен быть строкой C, то есть массивом с нулевым символом в char
.
Самое ценное, что он делает, это дать вам еще одну строку, идентичную первой, без необходимости выделять память (местоположение и размер) самостоятельно. Но, как уже отмечалось, вам все равно нужно освободить его (но это также не требует вычисления количества).
Это Simple strcpy(ptr2, ptr1)
эквивалентно while(*ptr2++ = *ptr1++)
, где as: strdup эквивалентно
ptr2 = malloc(strlen(ptr1)+1);
strcpy(ptr2,ptr1);
Итак, если вы хотите, чтобы строка, которую вы скопировали, использовалась в другой функции (поскольку она создана в разделе кучи), вы можете использовать strdup, иначе strcpy достаточно
strdupa()
. Эту функцию особенно интересно использовать, если вы говорите по-польски :).