Як скопіювати масив символів у 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.