Функция strdup выделяет память из кучи
есть также strdupa () (в библиотеке GNU C), хорошая функция, похожая на strdup (), но выделяющая память в стеке. Вашей программе не нужно явно освобождать память, как в случае с strdup (), она будет освобождена автоматически, когда вы выйдете из функции, из которой была вызвана strdupa ()
strdupa опасен и не должен использоваться, если вы уже не определили, что strlen очень маленький. Но тогда вы можете просто использовать массив фиксированного размера в стеке.
R.. GitHub STOP HELPING ICE
@slacker google translate бесполезен . Что означает strdup / strdupa на польском языке?
Просто пришел сюда, чтобы добавить, что и «дупа», и «нить» имеют какое-то отношение к заднице в польском языке.
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно.
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей.
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то.
Ответы 10
Функция strdup() должна возвращать указатель на новую строку, которая является дубликатом строки, на которую указывает s1 . Возвращенный указатель можно передать на free() . Если новая строка не может быть создана, возвращается нулевой указатель.
Он создает дублирующую копию переданной строки, выполняя маллок и strcpy переданной строки. Неправильный буфер возвращается вызывающей стороне, следовательно, необходимо запустить бесплатно для возвращаемого значения.
Самое ценное, что он делает, это дает вам другую строку, идентичную первой, без необходимости самостоятельно выделять память (расположение и размер). Но, как уже отмечалось, вам все равно нужно освободить его (но это тоже не требует подсчета количества).
В точности то, на что это похоже, если вы привыкли к сокращенному способу, которым C и UNIX назначают слова, это дублирует строки :-)
Имея в виду, что (a) на самом деле не является частью стандарта ISO C (это POSIX), он фактически делает то же самое, что и следующий код:
Он пытается выделить достаточно памяти для хранения старой строки (плюс символ '\ 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 :
Function names that begin with str , mem , or wcs and a lowercase letter may be added to the declarations in the header.
Так что вам, вероятно, следует назвать это как-нибудь иначе, если вы хотите быть в безопасности.
(b) В основном это изменение заключается в замене if (d == NULL) return NULL; на:
(c) Обратите внимание, что я использую для этого strcpy , поскольку это ясно показывает намерение. В некоторых реализациях может быть быстрее (поскольку длина вам уже известна) использовать memcpy , поскольку они могут позволять передавать данные большими порциями или параллельно. А может и нет :-) Оптимизационная мантра №1: «измеряйте, а не угадайте».
В любом случае, если вы решите пойти по этому пути, сделайте что-то вроде:
Стоит отметить, что, как следует из примера реализации 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 - Reinstate Monica
Хороший момент, @chux, ISO требует только < EDOM, EILSEQ, ERANGE >в качестве обязательных кодов ошибок. Обновили ответ, чтобы учесть это.
@paxdiablo, поскольку люди не часто читают другие ответы, пожалуйста, измените это, чтобы использовать memcpy вместо "канонической реализации strdup";)
@Antti, я не уверен, почему вы думаете, что вариант memcpy будет каноническим. Возможно, май будет быстрее, но я предпочитаю сначала оптимизировать для удобочитаемости :-)
Нет, вопрос это: D для тех, кто просит портировать strdup. Кстати, забавная вещь, GCC оптимизирует это для memcpy, но clang его пропускает.
I'm doing a lesson from the Learn C the Hard way online course. In the code sample below, I don't understand why the two free() calls are necessary. I thought one would only need to call free() once, because only one malloc() occurs. Could somebody clarify why we need two?
If I comment out free(who->name); then valgrind tells me that I've lost a chunk 'o memory, like so;
strdup is not a Standard C function, however it is in POSIX. (No Standard C functions return a pointer that requires freeing, other than malloc , calloc , realloc ).
1 Answer 1
BTW, as Matt McNabb commented, strdup is standard in Posix, not in the C99 language specification.
Of course free only releases the memory zone that you pass it (it does not magically and indirectly free any zone pointed inside the memory zone you pass it). Again, free(3) says:
Read much more about C dynamic memory allocation. If you don't like that, learn about garbage collection. With C on Linux and some other systems, you could consider using Boehm's conservative garbage collector. You'll then use GC_MALLOC and/or GC_MALLOC_ATOMIC instead of malloc , and GC_STRDUP instead of strdup and you won't bother about free (you might sometimes use GC_FREE if wanted). I find it very useful, but it does have some drawbacks (a bit slower than malloc , and no explicit guarantee about releasing memory. ).
BTW, you should first compile your program with all warnings and debug info (e.g. gcc -Wall -g ). Then you could use your debugger ( gdb ), set a breakpoint in malloc after main has been reached, and see when malloc is called. You'll see that strdup is calling malloc .
FYI, on Linux, malloc is implemented using mmap(2) -and sometimes the old sbrk(2)- syscalls -to get "large" memory regions (of several kilobytes or even megabytes), and free may sometimes call munmap(2) -for these large regions- but most often it justs mark a freed block as reusable, so that block could be reused in some future calls to malloc . Hence a program doing malloc and free might not release all it previously used memory to the kernel. See also this question about memory fragmentation.
use also Valgrind and the address sanitizer
On some operating systems (e.g. Linux) you could compile your C code (using GCC) using gcc -Wall -Wextra -g then use the valgrind tool at runtime. It slows down the execution, but it is helpful in finding bugs like some memory leaks and some buffer overflow. With a recent GCC or Clang compiler, you could also use -at compile time- its address sanitizer (instrumenting the generated code).
You might also read the GC handbook, related to memory allocation and garbage collection algorithms.
Does strdup allocate another memory zone and create another pointer every time?
For example: does the following code result in a memory leak?
@Barmar The program takes no inputs and produces no outputs, so how it could work without allocating memory could be like this int main() < return 0; >. A compiler is permitted to do this optimization, even.
3 Answers 3
Yes, the program leaks memory because it allocates objects and then loses references to them.
The first time this happens is in the line:
The variable test holds the one and only copy of a pointer that was allocated in a previous call to x . The new call to x overwrites that pointer. At that point, the pointer leaks.
This is what it means to leak memory: to lose all references to an existing dynamically allocated piece of storage.
The second leak occurs when the main function returns. At that point, the test variable is destroyed, and that variable holds the one and only copy of a pointer to a duplicate of the "etc" string.
Sometimes in C programs, we sometimes not care about leaks of this second type: memory that is not freed when the program terminates, but that is not allocated over and over again in a loop (so it doesn't cause a runaway memory growth problem).
If the program is ever integrated into another program (for instance as a shared library) where the original main function becomes a startup function that could be invoked repeatedly in the same program environment, both the leaks will turn into problems.
The POSIX strdup function behaves similarly to this:
Yes; it allocates new storage each time.
If you have a garbage collector (such as Boehm) in your C image, then it's possible that the leaked storage is recycled, and so strdup is able to re-use the same memory for the second allocation. (However, a garbage collector is not going to kick in after just one allocation, unless it is operated in a stress-test mode for flushing out bugs.)
Now if you want to actually reuse the memory with realloc, then you can change your x function along these lines:
(By the way, external names starting with str are in an ISO C reserved namespace, but strealloc is too nice a name to refuse.)
Note that the interface is different. We do not pass in a pointer-to-pointer, but instead present a realloc -like interface. The caller can check the return value for null to detect an allocation error, without having the pointer inconveniently overwritten with null in that case.
The main function now looks like:
Like before, there is no error checking. If the first strealloc were to fail, test is then null. That doesn't since it gets overwritten anyway, and the first argument of strealloc may be null.
будущие направления string.h можно найти в C11 7.31.13 String handling :
имена функций, которые начинаются с str , mem или wcs и строчная буква может быть добавлена к объявлениям в .
(b) изменение в основном будет заменять if (d == NULL) return NULL; С:
может быть, код немного быстрее, чем с strcpy() как char не нужно искать снова (это уже было с strlen() ).
нет смысла повторять другие ответы, но обратите внимание, что strdup() можно делать все, что хочет, с точки зрения C, так как он не является частью стандарта C. Однако он определяется POSIX.1-2001.
С strdup man:
The strdup() функция возвращает указатель на новую строку, которая является дубликатом строки, на которую указывает s1 . Возвращенный указатель может быть передан в free() . Если новая строка не может быть создана, возвращается нулевой указатель.
Он делает дубликат строки, переданной с помощью запуска malloc и strcpy переданной строки. Функции malloc и объед буфер возвращается вызывающему объекту, следовательно, необходимо работать свободный на возвращаемое значение.
strdup () выполняет динамическое выделение памяти для массива символов, включая конечный символ '\0', и возвращает адрес памяти кучи:
таким образом, он дает нам другую строку, идентичную строке, заданной его аргументом, не требуя от нас выделения памяти. Но мы все равно должны освободить его позже.
strdup и strndup определяются в POSIX-совместимых системах как:
The strdup () функция выделяет достаточно памяти для копии строка str , делает копию и возвращает указатель на него.
указатель может впоследствии использоваться в качестве аргумента функции free .
если недостаточно памяти, NULL и errno установлено ENOMEM .
в strndup() функция копирует не более len символы из строки str всегда null завершает скопированную строку.
самое ценное, что он делает, это дает вам другую строку, идентичную первой, не требуя от вас выделения памяти (местоположение и размер) самостоятельно. Но, как уже отмечалось, вам все равно нужно освободить его (но это также не требует расчета количества.)
функция strdup () является сокращением для дубликата строки, она принимает параметр как строковую константу или строковый литерал и выделяет достаточно места для строки и записывает соответствующие символы в выделенное пространство и, наконец, возвращает адрес выделенного пространства вызывающей подпрограмме.
Это просто strcpy(ptr2, ptr1) эквивалентно while(*ptr2++ = *ptr1++)
где: strdup эквивалентно
ptr2 = malloc(strlen(ptr1)+1);
strcpy(ptr2,ptr1);
поэтому, если вы хотите, чтобы строка, которую вы скопировали, использовалась в другой функции (так как она создана в разделе кучи) , вы можете использовать strdup, иначе strcpy достаточно
Есть также strdupa () (в библиотеке GNU C), хорошая функция, похожая на strdup (), но выделяющая память в стеке. Вашей программе не нужно явно освобождать память, как в случае с strdup (), она будет освобождена автоматически, когда вы выйдете из функции, из которой была вызвана strdupa ()
strdupa опасен и не должен использоваться, если вы уже не определили, что strlen очень маленький. Но тогда вы можете просто использовать массив фиксированного размера в стеке.
В точности то, на что это похоже, если предположить, что вы привыкли к сокращенному способу, которым C и UNIX присваивают слова, он дублирует строки :-)
Он пытается выделить достаточно памяти для хранения старой строки (плюс символ '\ 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 :
Имена функций, начинающиеся с str , mem или wcs и строчные буквы, могут быть добавлены к объявлениям в заголовке .
Так что вам, вероятно, следует называть это как-нибудь иначе, если вы хотите быть в безопасности.
(b) В основном это изменение заключается в замене if (d == NULL) return NULL; на:
(c) Обратите внимание, что я использую для этого strcpy , поскольку это ясно показывает намерение. В некоторых реализациях может быть быстрее (так как вы уже знаете длину) использовать memcpy , поскольку они могут позволить передавать данные большими порциями или параллельно. А может и нет :-) Оптимизационная мантра №1: «измеряйте, а не угадайте».
В любом случае, если вы решите пойти по этому пути, сделайте что-то вроде:
Стоит отметить, что, как следует из примера реализации Pax, strdup (NULL) не определен, а не то, что вы можете ожидать предсказуемым образом.
Кроме того, я думаю, что malloc () установит errno, поэтому вам не нужно устанавливать его самостоятельно. Думаю.
@Alcot, strdup предназначен для тех ситуаций, когда вы хотите выделить динамическую память для копии строки. В противном случае придется делать это самому. Если у вас уже есть достаточно большой буфер (malloc'ed или иначе), да, используйте strcpy .
@acgtyrant: если под стандартом вы имеете в виду стандарт ISO (настоящий стандарт C), нет, это не его часть. Это является частью стандарта POSIX. Однако существует множество C реализаций , которые предоставляют его, несмотря на то, что они не являются официальной частью ISO C. Однако, даже если они этого не сделали, пятистрочного ответа в этом ответе должно быть более чем достаточно .
Хороший замечание, @chux, ISO требует только < EDOM, EILSEQ, ERANGE >в качестве обязательных кодов ошибок. Обновили ответ, чтобы учесть это.
Может быть, код немного быстрее, чем с strcpy() , поскольку символ \0 не нужно искать снова (это уже было с strlen() ).
Спасибо. В своей личной реализации делаю еще «хуже». return memcpy(malloc(len), s, len); , поскольку я предпочитаю сбой при выделении, а не NULL при сбое выделения.
Разыменование NULL не должно приводить к сбою; это не определено. Если вы хотите быть уверенным, что произойдет сбой, напишите emalloc , который вызывает abort в случае сбоя.
Я знаю это, но моя реализация гарантированно работает только на Solaris или Linux (по самой природе приложения).
@tristopia: Хорошо иметь привычку делать все наилучшим образом. Возьмите за привычку использовать emalloc , даже если в этом нет необходимости в Solaris или Linux, чтобы вы могли использовать его в будущем, когда будете писать код на других платформах.
Нет смысла повторять другие ответы, но обратите внимание, что strdup() может делать все, что захочет, с точки зрения C, поскольку он не является частью какого-либо стандарта C. Однако он определен в POSIX.1-2001.
strdup() переносится? Нет, недоступно в среде, отличной от POSIX (в любом случае, это тривиально реализуемо). Но сказать, что функция POSIX может делать что угодно, довольно педантично. POSIX - еще один стандарт , не уступающий по качеству C и даже более популярный.
Я думаю, дело в том, что реализация C, не претендующая на соответствие POSIX, может по-прежнему предоставлять функцию strdup в качестве расширения. В такой реализации нет гарантии, что strdup будет вести себя так же, как функция POSIX. Я не знаю ни одной такой реализации, но законная невредоносная реализация может предоставить char *strdup(char *) по историческим причинам и отклонить попытки передать const char * .
В чем разница между стандартом C и POSIX? Под стандартом C вы имеете в виду, что его нет в стандартных библиотеках C?
Это разные стандарты. Лучше рассматривать их как несвязанные, если вы не знаете, что стандарт для конкретной функции C соответствует стандарту POSIX, а ваш компилятор / библиотека соответствует стандарту для этой функции.
Функция strdup() должна возвращать указатель на новую строку, которая является дубликатом строки, на которую указывает s1 . Возвращенный указатель можно передать на free() . Если новая строка не может быть создана, возвращается нулевой указатель.
Strdup () выполняет динамическое выделение памяти для массива символов, включая конечный символ '\ 0', и возвращает адрес кучи памяти:
Таким образом, он дает нам другую строку, идентичную строке, заданной его аргументом, не требуя от нас выделения памяти. Но нам все равно нужно освободить его позже.
Он создает дублирующую копию переданной строки, выполняя malloc и strcpy переданной строки. Буфер с ошибкой возвращается вызывающей стороне, следовательно, необходимо чтобы запустить бесплатно для возвращаемого значения.
strdup и strndup определены в POSIX-совместимых системах как:
Функция strdup () выделяет достаточно памяти для копии строка str , копирует и возвращает указатель на нее.
Указатель впоследствии может использоваться как аргумент функции free .
Если доступно недостаточно памяти, возвращается NULL и errno устанавливается на ENOMEM .
Функция strndup () копирует не более len символов из строки str , всегда завершая скопированную строку нулем.
Самое ценное, что он делает, это дает вам другую строку, идентичную первой, без необходимости самостоятельно выделять память (расположение и размер). Но, как уже отмечалось, вам все равно нужно освободить его (но это тоже не требует подсчета количества).
Эквивалентно (кроме того, что это изменяет указатели):
Итак, если вы хотите, чтобы скопированная вами строка использовалась в другой функции (поскольку она создается в разделе кучи), вы можете использовать strdup , иначе достаточно strcpy ,
Функция strdup () является сокращением для дубликата строки, она принимает параметр как строковую константу или строковый литерал, выделяет достаточно места для строки и записывает соответствующие символы в выделенное пространство и, наконец, возвращает адрес выделенного пространство для вызывающей процедуры.
Аргумент для strdup не обязательно должен быть строковой константой, это должна быть строка C, то есть массив char с завершающим нулем.
Читайте также: