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

242

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

  • 41
    есть также strdupa () (в библиотеке GNU C), хорошая функция, которая похожа на strdup (), но выделяет память в стеке. Ваша программа не должна явно освобождать память, как в случае с strdup (), она будет освобождена автоматически при выходе из функции, где была вызвана strdupa ()
  • 30
    @dmityugov: +1 для strdupa() . Эту функцию особенно интересно использовать, если вы говорите по-польски :).
Показать ещё 5 комментариев
Теги:
function
strdup

10 ответов

338
Лучший ответ

Точно, как это звучит, предполагая, что вы привыкли к сокращенному пути, в котором 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
}

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

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

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

  3. В противном случае распределение работало, поэтому мы копируем старую строку в новую строку и возвращаем новый адрес (на который вызывающий абонент отвечает за освобождение в какой-то момент).

Имейте в виду, что концептуальное определение. Любой архитектор библиотеки, заслуживающий своей зарплаты, может предоставить сильно оптимизированный код, предназначенный для конкретного используемого процессора.


(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;
}
  • 8
    Стоит отметить, что, как показывает пример реализации Pax, strdup (NULL) не определен, и вы не можете ожидать, что он будет вести себя любым предсказуемым образом.
  • 2
    Кроме того, я думаю, что malloc () установит errno, поэтому вам не нужно устанавливать его самостоятельно. Я думаю.
Показать ещё 11 комментариев
82
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()).

  • 0
    Благодарю. В моей личной реализации я делаю это еще хуже. return memcpy(malloc(len), s, len); как я предпочитаю сбой при распределении, а не NULL при сбое выделения.
  • 2
    @ Tristopia разыменование NULL не должно произойти сбой; это не определено Если вы хотите быть уверенным, что он выйдет из строя, напишите emalloc который вызывает abort при emalloc .
Показать ещё 2 комментария
50

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

  • 3
    Является ли strdup() переносимым? Нет, недоступно в среде, отличной от POSIX (в любом случае, легко реализуемо). Но сказать, что функция POSIX может делать что угодно, довольно педантично. POSIX - это еще один стандарт, который так же хорош, как C, и еще более популярен.
  • 2
    @BlueMoon Я думаю, дело в том, что реализация C, не претендующая на соответствие POSIX, все же может предоставить функцию strdup в качестве расширения. В такой реализации нет гарантии, что strdup ведет себя так же, как функция POSIX. Я не знаю ни одной такой реализации, но законная не злонамеренная реализация может предоставить char *strdup(char *) по историческим причинам и отклонить попытки передать const char * .
Показать ещё 2 комментария
16

Из strdup man:

Функция strdup() должна возвращать указатель на новую строку, которая является дубликатом строки, на которую указывает s1. Возвращаемый указатель можно передать в free(). Возвращает нулевой указатель, если новая строка не может быть создана.

3

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
}

Итак, что он делает, это дать нам еще одну строку, идентичную строке, заданной его аргументом, без необходимости выделять память. Но нам еще нужно освободить его позже.

3

Он создает дублируемую копию строки, переданной с помощью malloc и strcpy строки, переданной в. Буфер malloc'ed возвращается вызывающему, следовательно, необходимо запустить бесплатно по возвращаемому значению.

2

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 всегда нулевая, заканчивая скопированную строку.

1

Функция strdup() является сокращением для строкового дубликата, она принимает параметр как строчную константу или строковый литерал и выделяет достаточно места для строки и записывает соответствующие символы в выделенном пространстве и, наконец, возвращает адрес от выделенного пространства к вызывающей процедуре.

  • 0
    Аргумент strdup не обязательно должен быть строковой константой, он должен быть строкой C, то есть массивом с нулевым символом в char .
1

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

0

Это Simple strcpy(ptr2, ptr1) эквивалентно while(*ptr2++ = *ptr1++)

, где as: strdup эквивалентно

ptr2 = malloc(strlen(ptr1)+1);

strcpy(ptr2,ptr1);

Итак, если вы хотите, чтобы строка, которую вы скопировали, использовалась в другой функции (поскольку она создана в разделе кучи), вы можете использовать strdup, иначе strcpy достаточно

Ещё вопросы

Сообщество Overcoder
Наверх
Меню