Strdup () - что он делает в C?

Какова цель функции strdup() в C?

есть также strdupa () (в библиотеке GNU C), хорошая функция, похожая на strdup (), но выделяющая память в стеке. Вашей программе не нужно явно освобождать память, как в случае с strdup (), она будет освобождена автоматически, когда вы выйдете из функции, из которой была вызвана strdupa ()

dmityugov 31.10.2008 16:05
strdupa опасен и не должен использоваться, если вы уже не определили, что strlen очень маленький. Но тогда вы можете просто использовать массив фиксированного размера в стеке.
R.. GitHub STOP HELPING ICE 29.12.2010 19:34

@slacker google translate бесполезен ... Что означает strdup / strdupa на польском языке?

haneefmubarak 07.03.2015 19:47

@haneefmubarak здесь

anatolyg 30.09.2015 20:02

Вот разница между strdup и strcpy stackoverflow.com/questions/14020380/strcpy-vs-strdup

Siva Prakash 21.08.2018 11:31

Просто пришел сюда, чтобы добавить, что и «дупа», и «нить» имеют какое-то отношение к заднице в польском языке.

Big Temp 11.05.2020 23:02
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
311
6
404 720
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

От мужчина:

Функция 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
}

Другими словами:

  1. Он пытается выделить достаточно памяти для хранения старой строки (плюс символ '\ 0' для обозначения конца строки).

  2. Если распределение не удалось, он устанавливает errno в ENOMEM и немедленно возвращает NULL. Установка errno на ENOMEM - это то, что malloc делает в POSIX, поэтому нам не нужно явно делать это в нашем strdup. Если вы совместимы с нет POSIX, ISO C фактически не требует наличия ENOMEM, поэтому я не включил это здесь (b).

  3. В противном случае выделение сработало, поэтому мы копируем старую строку в новую строку (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, or wcs and 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) не определен, а не то, что вы можете ожидать предсказуемым образом.

unwind 22.05.2009 14:14

Кроме того, я думаю, что malloc () установит errno, поэтому вам не нужно устанавливать его самостоятельно. Я думаю.

Chris Lutz 08.06.2009 07:58

Это хороший аргумент, @Chris. Я изменил его, потому что мне нужно было посмотреть справочную страницу для strdup (), и я заметил, что я это не упомянул. Но я забыл, что это сделала malloc (). Поэтому я верну код.

paxdiablo 08.06.2009 08:09

При наличии strcpy какой смысл в strdup? Безопаснее для строкового копирования?

Alcott 28.02.2012 04:51

@Alcot, strdup предназначен для тех ситуаций, когда вы хотите выделить память кучи для копии строки. В противном случае придется делать это самому. Если вы уже имеют достаточно большого буфера (malloc'ed или иначе), да, используйте strcpy.

paxdiablo 28.02.2012 05:15

Было бы неплохо иметь пример того, как его использовать

puk 06.11.2013 22:13

Есть ли сейчас какая-либо стандартная реализация или реализация C, поддерживающая эту функцию? Спасибо!

acgtyrant 16.04.2014 11:44

@acgtyrant: если под стандартом вы имеете в виду стандарт ISO (настоящий стандарт C), нет, это не его часть. Это является часть стандарта POSIX. Однако существует множество C реализации, которые предоставляют его, несмотря на то, что они не являются официальной частью ISO C. Однако, даже если они этого не сделали, пятистрочного ответа в этом ответе должно быть более чем достаточно.

paxdiablo 16.04.2014 14:37

Что ж, чувствую себя идиотом. «В точности как это звучит» -> повторял себе «str-d-up», думая, что это метод обсадной колонны.

jdknight 18.09.2014 19:18

@paxdiablo IIRC, «Если распределение не удалось, он устанавливает errno в ENOMEM» - это спецификация POSIX, а не C. Если код должен создать strdup(), скорее всего, не в системе POSIX, может ли malloc() также не установить errno? Таким образом, чтобы обеспечить функциональность, подобную POSIX, возможно, этот strdup() должен также установить errno по мере необходимости. В противном случае код вызова не должен рассчитывать на переход от errno к ENOMEM в случае сбоя через этот strdup().

chux - Reinstate Monica 30.01.2018 07:29

Хороший момент, @chux, ISO требует только { EDOM, EILSEQ, ERANGE } в качестве обязательных кодов ошибок. Обновили ответ, чтобы учесть это.

paxdiablo 30.01.2018 09:13

@paxdiablo, поскольку люди не часто читают другие ответы, пожалуйста, измените это, чтобы использовать memcpy вместо "канонической реализации strdup";)

Antti Haapala 22.04.2019 14:28

@Antti, я не уверен, почему вы думаете, что вариант memcpy будет каноническим. Возможно, май будет быстрее, но я предпочитаю сначала оптимизировать для удобочитаемости :-)

paxdiablo 23.04.2019 01:16

Нет, вопрос это: D для тех, кто просит портировать strdup. Кстати, забавная вещь, GCC оптимизирует это для memcpy, но clang его пропускает.

Antti Haapala 23.04.2019 01:19

@AnttiHaapala, добавили сноску по этому поводу.

paxdiablo 23.04.2019 04:36

Нет смысла повторять другие ответы, но обратите внимание, что strdup() может делать все, что захочет, с точки зрения C, поскольку он не является частью какого-либо стандарта C. Однако он определен в POSIX.1-2001.

strdup() портативный? Нет, недоступно в среде, отличной от POSIX (в любом случае, это тривиально реализуемо). Но сказать, что функция POSIX может делать что угодно, довольно педантично. POSIX - это еще один стандарт, который не уступает C и даже более популярен.

P.P 09.05.2014 12:58

@BlueMoon Я думаю, дело в том, что реализация C, которая заявляет о несоответствии POSIX, может по-прежнему предоставлять функцию strdup в качестве расширения. В такой реализации нет гарантии, что strdup ведет себя так же, как функция POSIX. Я не знаю ни одной такой реализации, но законная невредоносная реализация может предоставить char *strdup(char *) по историческим причинам и отклонить попытки передать const char *.

user743382 07.03.2015 01:19

В чем разница между стандартом C и POSIX? Под стандартом C вы имеете в виду, что его нет в стандартных библиотеках C?

Koray Tugay 22.03.2015 14:35

@KorayTugay Это разные стандарты. Лучше рассматривать их как несвязанные, если вы не знаете, что стандарт для конкретной функции C соответствует стандарту POSIX, а ваш компилятор / библиотека соответствует стандарту для этой функции.

Matthew Read 23.03.2015 22:40
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 при сбое выделения.

Patrick Schlüter 31.12.2010 00:00

@tristopia разыменование NULL не должно приводить к сбою; это не определено. Если вы хотите быть уверенным, что он выйдет из строя, напишите emalloc, который в случае ошибки вызывает abort.

Dave 30.12.2011 07:28

Я знаю это, но моя реализация гарантированно работает только на Solaris или Linux (по самой природе приложения).

Patrick Schlüter 30.12.2011 17:01

@tristopia: Хорошо иметь привычку делать все наилучшим образом. Возьмите за привычку использовать emalloc, даже если он не нужен в Solaris или Linux, чтобы вы могли использовать его в будущем, когда будете писать код на других платформах.

ArtOfWarfare 28.02.2015 23:20

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 с завершающим нулем.

chqrlie 18.08.2018 14:03

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,

Другие вопросы по теме