Як скопіювати масив символів у C?


79

У C я маю два масиви char:

Як скопіювати значення array1to array2? Чи можу я просто зробити це array2 = array1:?


3
strcpyабо memcpy.
— Алок Зберегти

1
char array1[18] = {"abcdefg"};не є належним масивом символів.
— aragaer

Використовуйте функцію strcpy (array2, array1)
— Рохан,

1
Незважаючи на те, що він працює як масив char (просто працює), його слід або оголосити як, char array1[18] = "abcdefg";абоchar array1[18] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', '\0'};
— aragaer

13
@aragaer 6.7.9 (14): "Масив типу символів може бути ініціалізований символьним рядковим літералом або UTF-8 рядковим літералом, необов'язково вкладеним у фігурні дужки ". char array1[18] = {"abcdefg"};незвично, але 100% пукка.
— Даніель Фішер

Відповіді:


84

Ви не можете безпосередньо це зробити array2 = array1, оскільки в цьому випадку ви маніпулюєте адресами масивів ( char *), а не їх внутрішніми значеннями ( char).

Що вам, концептуально, хочеться зробити, це перебрати всі символи вашого джерела ( array1 ) і скопіювати їх до місця призначення ( array2 ). Є кілька способів зробити це. Наприклад, ви можете написати простий цикл for, або використовувати memcpy.

З огляду на це, рекомендованим способом для рядків є використання strncpy. Це запобігає типовим помилкам, що призводять, наприклад, до переповнення буфера (що особливо небезпечно, якщо array1заповнюється за допомогою вводу користувача: клавіатури, мережі тощо). Подобається так:

Як @Prof. Фалькен, згаданий у коментарі, strncpy може бути злим . Переконайтеся, що цільовий буфер достатньо великий, щоб містити вихідний буфер (включаючи \0кінець рядка).



чому ми не можемо просто зробити array2 = array1?
— user2131316

2
@ user2131316: Це через спосіб семантичного перетворення імен масивів у значення покажчика. Я пояснюю це у своїй відповіді.
— jxh

Мене збентежило те, що ви згадали array1=array2, що означає, що array1 отримує нове значення, але ваш код робить це навпаки. Про всяк випадок, якщо хтось інший на це впаде.
— lucidbrot

strncat завжди буде надавати результат, закінчений нулем, без переповнення буфера. Дивіться це .
— Louis Go

36

Якщо ваші масиви не є масивами рядків, використовуйте: memcpy(array2, array1, sizeof(array2));


20
Перший аргумент memcpy - це цільовий масив, який повинен бути array2!
— Берт Регелінк

Чи не sizeof () повертає розмір покажчика (тобто розмір слова на вашій машині)?
— Вехеровський

1
@Wecherowski: Коли ви передаєте масив функції, вона знижується до покажчика. sizeof()Тоді в цій функції ви не можете визначити розмір масиву. В іншому випадку це sizeof()добре працює.
— Багфінгер

26

Якщо ви хочете захиститися від незавершених рядків, які можуть спричинити всілякі проблеми, скопіюйте свій рядок таким чином:

Цей останній рядок насправді важливий, оскільки strncpy()не завжди нуль закінчує рядки. (Якщо буфер призначення занадто малий, щоб містити весь вихідний рядок, sntrcpy () не буде нульовим завершенням цільового рядка.)

У керівництві для strncpy () навіть зазначено "Попередження: Якщо серед перших n байт src немає нульового байта, рядок, розміщений у dest, не буде закінчуватися нулем."

Причина, по якій strncpy () поводиться дещо дивно, полягає в тому, що вона насправді спочатку не задумувалася як безпечний спосіб копіювання рядків.

Інший спосіб - використовувати snprintf () як безпечну заміну strcpy ():

(Дякую jxh за підказку.)


2
Зверніть увагу, що у вас snprintf()немає проблеми, яка strncpy()має.
— jxh

Чи не генерує це попередження? strncpy приймає const char як джерело.
— kon psych

@konpsych, який не повинен генерувати попередження.
— Проф. Фалькен

6

Ви не можете призначити масиви, імена - це константи, які не можна змінити.

Ви можете скопіювати вміст за допомогою:

припускаючи, що джерелом є дійсний рядок і що пункт призначення достатньо великий, як у вашому прикладі.


5

Як зазначали інші, рядки копіюються з strcpy()або його варіантами. У певних випадках ви можете також використовувати snprintf().

Ви можете призначити масиви лише так, як вам потрібно, як частину призначення структури:

Якщо ваші масиви передаються функції, здається, що вам дозволено їх призначати, але це просто випадковість семантики. У C масив перетворюється на тип покажчика зі значенням адреси першого члена масиву, і цей покажчик передається. Отже, ваш параметр масиву у вашій функції насправді є лише покажчиком. Призначення - це просто призначення покажчика:

Сам масив залишається незмінним після повернення з функції.

Ця семантика "спаду до значення покажчика" для масивів є причиною того, що призначення не працює. Значення l має тип масиву, але значення r є типом впалого вказівника, тому присвоєння відбувається між несумісними типами.

Щодо того, чому було введено семантику "спаду до значення покажчика", це було для досягнення сумісності вихідного коду з попередником C. Ви можете прочитати Детальніше про розробку мови C.


Єдина відповідь, яка пояснює, чому array2 = array1;не працює. Проголосувати.
— Мілжен Мікіч

3

це повинно виглядати так:


1
Ваша cstringcpyфункція не закінчує нуль завершення цільового масиву.
— chqrlie

не зрозумів. будь ласка, надайте своє "виправлення".
— Борис

@ zett42: зауважте, що ця cstringcpyфункція майже точно семантично еквівалентна strcpy, з тими ж недоліками, а саме не перевіряє переповнення буфера.
— chqrlie

2

Я рекомендую використовувати memcpy () для копіювання даних. Крім того, якщо ми призначаємо буфер іншому як array2 = array1, обидва масиви мають однакову пам'ять, і будь-яка зміна arrar1 відхиляється в array2. Але ми використовуємо memcpy, обидва буфери мають різний масив. Я рекомендую memcpy (), оскільки strcpy та відповідна функція не копіюють символ NULL.


1

не підтримується в c. Для цього потрібно використовувати такі функції, як strcpy () .


1

функції c лише нижче ... c ++ вам потрібно зробити масив char, потім скопіювати рядок, а потім скористатися функцією tokenizor рядка ... c ++ набагато важче робити щось


0

для цілочисельних типів


1
Це не компілюється. Використовуйте int array1[10] = {0,1,2,3,4,5,6,7,8,9};замість цього.
— Тім

0

Ви не можете призначити масиви для їх копіювання. Спосіб копіювання вмісту одного в інший залежить від багатьох факторів:

Для charмасивів, якщо ви знаєте , що вихідний масив є нулем і цільової масив досить велике для рядка в початковому масиві, в тому числі нульового термінатора, використання strcpy():

Якщо ви не знаєте, чи достатньо великий масив призначення, але джерелом є рядок C, і ви хочете, щоб призначення було правильним рядком C, використовуйте snprinf():

Якщо вихідний масив не обов'язково закінчується нулем, але ви знаєте, що обидва масиви мають однаковий розмір, ви можете використовувати memcpy:


0

Ну, технічно ви можете ...

але це буде виглядати не дуже красиво.

... Якщо ви не використовуєте препроцесор C ...

Потім ви можете зробити:

І це буде працювати з будь-яким типом даних, а не тільки char:

(Так, вище код надається на роботу завжди , і це портативний)


0

Жодне з перерахованого вище не працювало для мене .. це чудово працює nameось char *nameщо передається через функцію

  1. отримати тривалість char *nameвикористанняstrlen(name)
  2. важливо зберігати його у змінній const
  3. створити charмасив однакової довжини
  4. копіювати nameвміст до tempвикористанняstrcpy(temp, name);

використовуйте як завгодно, якщо хочете повернути оригінальний вміст. strcpy(name, temp);скопіювати temp назад до nameі voila працює ідеально

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