Какова цель функции strdup() в C?
strdupa опасен и не должен использоваться, если вы уже не определили, что strlen очень маленький. Но тогда вы можете просто использовать массив фиксированного размера в стеке.
@slacker google translate бесполезен ... Что означает strdup / strdupa на польском языке?
@haneefmubarak здесь
Вот разница между strdup и strcpy stackoverflow.com/questions/14020380/strcpy-vs-strdup
Просто пришел сюда, чтобы добавить, что и «дупа», и «нить» имеют какое-то отношение к заднице в польском языке.





От мужчина:
Функция strdup() должна возвращать указатель на новую строку, которая является дубликатом строки, на которую указывает s1. Возвращенный указатель можно передать на free(). Если новая строка не может быть создана, возвращается нулевой указатель.
Он создает дублирующую копию переданной строки, выполняя маллок и strcpy переданной строки. Неправильный буфер возвращается вызывающей стороне, следовательно, необходимо запустить бесплатно для возвращаемого значения.
Самое ценное, что он делает, это дает вам другую строку, идентичную первой, без необходимости самостоятельно выделять память (расположение и размер). Но, как уже отмечалось, вам все равно нужно освободить его (но это тоже не требует подсчета количества).
В точности то, на что это похоже, если вы привыкли к сокращенному способу, которым C и UNIX назначают слова, это дублирует строки :-)
Имея в виду, что (a) на самом деле не является частью стандарта 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:
Each header declares or defines all identifiers listed in its associated sub-clause, and *optionally declares or defines identifiers listed in its associated future library directions sub-clause.**
Будущие направления для string.h можно найти в C11 7.31.13 String handling <string.h>:
Function names that begin with
str,mem, orwcsand a lowercase letter may be added to the declarations in the<string.h>header.
Так что вам, вероятно, следует назвать это как-нибудь иначе, если вы хотите быть в безопасности.
(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
}
Стоит отметить, что, как следует из примера реализации Pax, strdup (NULL) не определен, а не то, что вы можете ожидать предсказуемым образом.
Кроме того, я думаю, что malloc () установит errno, поэтому вам не нужно устанавливать его самостоятельно. Я думаю.
Это хороший аргумент, @Chris. Я изменил его, потому что мне нужно было посмотреть справочную страницу для strdup (), и я заметил, что я это не упомянул. Но я забыл, что это сделала malloc (). Поэтому я верну код.
При наличии strcpy какой смысл в strdup? Безопаснее для строкового копирования?
@Alcot, strdup предназначен для тех ситуаций, когда вы хотите выделить память кучи для копии строки. В противном случае придется делать это самому. Если вы уже имеют достаточно большого буфера (malloc'ed или иначе), да, используйте strcpy.
Было бы неплохо иметь пример того, как его использовать
Есть ли сейчас какая-либо стандартная реализация или реализация C, поддерживающая эту функцию? Спасибо!
@acgtyrant: если под стандартом вы имеете в виду стандарт ISO (настоящий стандарт C), нет, это не его часть. Это является часть стандарта POSIX. Однако существует множество C реализации, которые предоставляют его, несмотря на то, что они не являются официальной частью ISO C. Однако, даже если они этого не сделали, пятистрочного ответа в этом ответе должно быть более чем достаточно.
Что ж, чувствую себя идиотом. «В точности как это звучит» -> повторял себе «str-d-up», думая, что это метод обсадной колонны.
@paxdiablo IIRC, «Если распределение не удалось, он устанавливает errno в ENOMEM» - это спецификация POSIX, а не C. Если код должен создать strdup(), скорее всего, не в системе POSIX, может ли malloc() также не установить errno? Таким образом, чтобы обеспечить функциональность, подобную POSIX, возможно, этот strdup() должен также установить errno по мере необходимости. В противном случае код вызова не должен рассчитывать на переход от errno к ENOMEM в случае сбоя через этот strdup().
Хороший момент, @chux, ISO требует только { EDOM, EILSEQ, ERANGE } в качестве обязательных кодов ошибок. Обновили ответ, чтобы учесть это.
@paxdiablo, поскольку люди не часто читают другие ответы, пожалуйста, измените это, чтобы использовать memcpy вместо "канонической реализации strdup";)
@Antti, я не уверен, почему вы думаете, что вариант memcpy будет каноническим. Возможно, май будет быстрее, но я предпочитаю сначала оптимизировать для удобочитаемости :-)
Нет, вопрос это: D для тех, кто просит портировать strdup. Кстати, забавная вещь, GCC оптимизирует это для memcpy, но clang его пропускает.
@AnttiHaapala, добавили сноску по этому поводу.
Нет смысла повторять другие ответы, но обратите внимание, что strdup() может делать все, что захочет, с точки зрения C, поскольку он не является частью какого-либо стандарта C. Однако он определен в POSIX.1-2001.
strdup() портативный? Нет, недоступно в среде, отличной от POSIX (в любом случае, это тривиально реализуемо). Но сказать, что функция POSIX может делать что угодно, довольно педантично. POSIX - это еще один стандарт, который не уступает C и даже более популярен.
@BlueMoon Я думаю, дело в том, что реализация C, которая заявляет о несоответствии POSIX, может по-прежнему предоставлять функцию strdup в качестве расширения. В такой реализации нет гарантии, что strdup ведет себя так же, как функция POSIX. Я не знаю ни одной такой реализации, но законная невредоносная реализация может предоставить char *strdup(char *) по историческим причинам и отклонить попытки передать const char *.
В чем разница между стандартом C и POSIX? Под стандартом C вы имеете в виду, что его нет в стандартных библиотеках C?
@KorayTugay Это разные стандарты. Лучше рассматривать их как несвязанные, если вы не знаете, что стандарт для конкретной функции C соответствует стандарту POSIX, а ваш компилятор / библиотека соответствует стандарту для этой функции.
char * strdup(const char * s)
{
size_t len = 1+strlen(s);
char *p = malloc(len);
return p ? memcpy(p, s, len) : NULL;
}
Возможно, код немного быстрее, чем с strcpy(), поскольку символ \0 не требует повторного поиска (это уже было с strlen()).
Спасибо. В своей личной реализации делаю еще «хуже». return memcpy(malloc(len), s, len);, поскольку я предпочитаю сбой при выделении, а не NULL при сбое выделения.
@tristopia разыменование NULL не должно приводить к сбою; это не определено. Если вы хотите быть уверенным, что он выйдет из строя, напишите emalloc, который в случае ошибки вызывает abort.
Я знаю это, но моя реализация гарантированно работает только на Solaris или Linux (по самой природе приложения).
@tristopia: Хорошо иметь привычку делать все наилучшим образом. Возьмите за привычку использовать emalloc, даже если он не нужен в Solaris или Linux, чтобы вы могли использовать его в будущем, когда будете писать код на других платформах.
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
}
Таким образом, он дает нам другую строку, идентичную строке, заданной его аргументом, не требуя от нас выделения памяти. Но нам все равно нужно освободить его позже.
Функция strdup () является сокращением для дубликата строки, она принимает параметр как строковую константу или строковый литерал, выделяет достаточно места для строки и записывает соответствующие символы в выделенное пространство и, наконец, возвращает адрес выделенного пространство для вызывающей процедуры.
Аргумент strdup не обязательно должен быть строковой константой, это должна быть строка C, то есть массив char с завершающим нулем.
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, всегда завершая скопированную строку нулем.
Заявление:
strcpy(ptr2, ptr1);
эквивалентно (кроме того, что это изменяет указатели):
while(*ptr2++ = *ptr1++);
Тогда как:
ptr2 = strdup(ptr1);
эквивалентно:
ptr2 = malloc(strlen(ptr1) + 1);
if (ptr2 != NULL) strcpy(ptr2, ptr1);
Итак, если вы хотите, чтобы строка, которую вы скопировали, использовалась в другой функции (поскольку она создается в разделе кучи), вы можете использовать strdup, иначе достаточно strcpy,
есть также strdupa () (в библиотеке GNU C), хорошая функция, похожая на strdup (), но выделяющая память в стеке. Вашей программе не нужно явно освобождать память, как в случае с strdup (), она будет освобождена автоматически, когда вы выйдете из функции, из которой была вызвана strdupa ()