strcpy проти strdup


74

Я прочитав, що strcpyпризначено для копіювання рядка, і strdupповертає покажчик на новий рядок, щоб дублювати рядок.

Не могли б ви пояснити, які кейси ви віддаєте перевагу використовувати strcpyі які кейси ви віддаєте перевагу використовувати strdup?

Відповіді:


106

strcpy(ptr2, ptr1) еквівалентно while(*ptr2++ = *ptr1++)

де як strdup еквівалентно

( версія memcpy може бути більш ефективною)

Отже, якщо ви хочете, щоб рядок, який ви скопіювали, використовувався в іншій функції (оскільки вона створюється в розділі купи), ви можете використовувати strdup, інакше strcpy досить.


6
Хороша відповідь, крім останнього речення, яке бентежить. Думаю, ви маєте на увазі, що термін служби strdup()рядка ed може продовжуватись і до кінця поточної функції, але це може бути так чи інакше (якщо ціль strcpy()- це буфер, що надається абонентом, глобальна змінна або сам вручну за допомогою malloc()або new) .
j_random_hacker

1
Так, це правда, що якщо буфер, що надається абонентом, є глобальною змінною або динамічним покажчиком сам по собі, тоді немає необхідності використовувати strdup, я щойно вказав один із сценаріїв використання та дякую за заповнення.
Абдул Мухід

9
Дуже люблю while(*ptr2++ = *ptr1++)! :)
Aloys

1
У циклі while, як працює умова виходу?
sbhatla

3
@sbhatla У C рядки закінчуються нульбайтом, який обчислюється як false, а вираз присвоєння - за присвоєним значенням.

56

Функції strcpyта strncpyє частиною стандартної бібліотеки C і працюють на наявній пам'яті. Тобто ви повинні надати пам’ять, в яку функції копіюють рядкові дані, і як наслідок, ви повинні мати власні засоби, щоб з’ясувати, скільки вам потрібно пам’яті.

За обмеженням, strdupце функція Posix, і вона виконує для вас динамічне розподіл пам'яті. Він повертає покажчик на нещодавно виділену пам’ять, в яку він скопіював рядок. Але ви тепер відповідальні за цю пам’ять і, зрештою, повинні freeїї.

Це робить strdupодну із "прихованих malloc" зручних функцій, і, мабуть, саме тому вона не є частиною стандартної бібліотеки. Поки ви використовуєте стандартну бібліотеку, ви знаєте, що ви повинні викликати по одній freeдля кожного malloc/ calloc. Але такі функції, як strdupвведення прихованого malloc, ви повинні обробляти так само, як і mallocдля цілей управління пам'яттю. (Ще однією такою прихованою функцією розподілу є GCC abi::__cxa_demangle().) Обережно!


1
Ааа, я завжди дивувався, чому цього не було в stdlib, і тепер я знаю.
Морі Марковіц,

14

strdupвиділяє пам'ять для нового рядка в купі, при використанні strcpy(або його більш безпечним strncpyvarient) Я можу скопіювати рядок в виділеної пам'яті заздалегідь на будь-який купі або стеку.


1
Чому рішуче "або"? Чи не можна strcpyскопіювати в статичний буфер?
Kerrek SB

Я намагався наголосити на різниці у використанні двох функцій, не захаращуючи відповідь занадто багатьма проблемами з управлінням пам'яттю. але так, ви маєте рацію щодо статичних буферів.
Орен

Якщо ви не хочете безладу, можете просто закінчити відповідь після "попередньо виділеної пам'яті" :-)
Kerrek SB

small nitpick: strncpy не безпечніший за strcpy, оскільки це не гарантує, що dest буде припинено. Навіть гірше, будь-який невикористаний простір у буфері dest буде заповнений нульовими термінаторами. Ця функція ніколи не була призначена для загального користування. Якщо вам потрібно використовувати одну з цих функцій, найкраще використовувати strcpy і вручну завершити призначення.
JohnF

11

У прийнятій відповіді реалізація strdupпредставлена ​​як:

Однак це дещо неоптимально, оскільки обидва strlenі strcpyпотрібно знайти довжину рядка, перевіривши, чи кожен символ є \0.

Використання memcpyповинно бути більш ефективним:


1
Хороша відповідь, яка відокремлює концептуальне використання strcpyреалізації strdupвід практичної ефективності.
Майкл Гаскілл

Враховуючи, що memcpy залежить від знання довжини рядка, strlen буде викликатися в будь-якому випадку. Сам memcpy еквівалентний while ( len-- ) { *ptr2++ = *ptr1++ }, який кожного разу виконує віднімання, присвоєння та перевірку на нуль, а потім все одно повинен виконати присвоєння, а потім два кроки після публікації та їх призначення в будь-якому випадку. Тож ця техніка memcpy здається менш ефективною. Це здається досить тривіальними розбіжностями та уявною оптимізацією.

0

char *strdup(char *pszSrch);

strdupвиділить пам'ять розміром вихідного рядка. У разі успішного розподілу пам’яті оригінальний рядок копіюється у повторюваний рядок.

strdupd повернення NULLпри відмові. Якщо пам'ять не виділено, копія не strdupповертається NULL.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.