Чи існує функція копіювання масиву в C / C ++?


91

Я програміст Java, який вивчає C / C ++. Тому я знаю, що Java має таку функцію, як System.arraycopy (); скопіювати масив. Мені було цікаво, чи є в C або C ++ функція для копіювання масиву. Я зміг знайти реалізацію для копіювання масиву лише за допомогою циклу for, покажчиків тощо. Чи є функція, яку я можу використати для копіювання масиву?


7
man memmoveтаman memcpy
Тім Купер

28
Не користуйся memcpy, використовуй std::copy. Якщо у вашому типі є конструктивний конструктор копіювання, тоді memcpyви зробите неправильно.
Ed S.

10
Ви насправді намагаєтесь вивчити C і C ++ одночасно? Це дуже різні мови.
Ферруччо

1
Ну, я вивчив трохи C, і ось нещодавно я почав вивчати C ++. З того, що я прочитав з Інтернет-ресурсу, я думав, що C ++ - це просто мова з великою кількістю додаткових функцій до мови C.
JL

6
Я кажу це тому, що про це раніше ніхто не згадував: У C ++ майже у всіх випадках слід використовувати std :: vector. Бувають випадки, коли інші контейнери теж корисні, але в більшості випадків найкращим варіантом буде std :: vector. Не використовуйте необроблені масиви в C ++ і намагайтеся уникати std :: array, якщо це не потрібно.
Скаллі

Відповіді:


79

З C ++ 11 ви можете копіювати масиви безпосередньо за допомогою std::array:

std::array<int,4> A = {10,20,30,40};
std::array<int,4> B = A; //copy array A into array B

Ось документація щодо std :: array


@XAleXOwnZX: Те саме, що і будь-який інший тип, який підтримує призначення копій. B = A.
swalog

2
Я думаю, що функція копіює адресу пам’яті A в B. Якщо я спробую скопіювати значення елементів A у B, не змінюючи адресу пам'яті B. Як я можу це зробити?
Аарон Лі

@Aaron_Lee: Я щойно перевірив його, і він справді копіює елементи в масив в окремому місці пам'яті. Клас масиву, очевидно, має власне перевантаження для оператора присвоєння.
Дейв Роув,

4
Ви, хлопці, розумієте, що в цих двох рядках коду не з’явилося жодного оператора присвоєння, так? Це викликається конструктор копіювання, хоча позначення виглядає як оператор присвоєння.
Альбіно Кордейру

137

Оскільки ви попросили рішення C ++ ...

#include <algorithm>
#include <iterator>

const int arr_size = 10;
some_type src[arr_size];
// ...
some_type dest[arr_size];
std::copy(std::begin(src), std::end(src), std::begin(dest));

2
erreur: 'begin' не є членом 'std'
Девід 天宇 Вонг

23
@David 天宇 Вонг: Ви використовуєте старий компілятор або не включили заголовок. Це в<iterator>
Ed S.

9
Можливо, вам слід сказати, що саме вам потрібно. Чи є копія <algorithm>?
Джеррі Єремія

15
Я лише запитую, тому що якщо вам довелося пояснити, що std :: begin був у <iterator>, це означає, що люди не шукають у google std :: start, щоб дізнатись, в якому заголовку він знаходиться, тому вони навряд чи зможуть загуглити std :: copy для того самого причина. Це дає кращу відповідь, якщо ніхто не повинен запитувати речі, на які відповідають лише в коментарях. Можливо, мені слід було просто відредагувати відповідь, а не спонукати вас це зробити.
Джеррі Єремія

3
ти можеш змінити початок (src) на src і кінець (src) на src + arr_size
Кальвін

82

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

У C ++ ви також можете використовувати, memcpyякщо члени вашого масиву є POD (тобто, по суті, типи, які ви також могли б використовувати в незміненому вигляді на C), але загалом memcpyце не дозволено. Як згадували інші, функцією, яку потрібно використовувати, є std::copy.

Сказавши це, в C ++ вам рідко слід використовувати необроблені масиви. Натомість вам слід скористатися одним із стандартних контейнерів ( std::vectorє найближчим до вбудованого масиву, а також, на мою думку, найближчим до масивів Java - справді ближчим, ніж звичайні масиви С ++, але, std::dequeабо std::listв деяких випадках може бути більш доречним) або, якщо ви використовуєте С ++ 11, std::arrayякий дуже близький до вбудованих масивів, але із семантикою значень, як інші типи С ++. Усі типи, про які я згадав тут, можна скопіювати шляхом призначення або побудови копії. Більше того, ви можете "перехресно копіювати" з opne на інший (і навіть із вбудованого масиву), використовуючи синтаксис ітератора.

Це дає огляд можливостей (я вважаю, що всі відповідні заголовки були включені):

int main()
{
  // This works in C and C++
  int a[] = { 1, 2, 3, 4 };
  int b[4];
  memcpy(b, a, 4*sizeof(int)); // int is a POD

  // This is the preferred method to copy raw arrays in C++ and works with all types that can be copied:
  std::copy(a, a+4, b);

  // In C++11, you can also use this:
  std::copy(std::begin(a), std::end(a), std::begin(b));

  // use of vectors
  std::vector<int> va(a, a+4); // copies the content of a into the vector
  std::vector<int> vb = va;    // vb is a copy of va

  // this initialization is only valid in C++11:
  std::vector<int> vc { 5, 6, 7, 8 }; // note: no equal sign!

  // assign vc to vb (valid in all standardized versions of C++)
  vb = vc;

  //alternative assignment, works also if both container types are different
  vb.assign(vc.begin(), vc.end());

  std::vector<int> vd; // an *empty* vector

  // you also can use std::copy with vectors
  // Since vd is empty, we need a `back_inserter`, to create new elements:
  std::copy(va.begin(), va.end(), std::back_inserter(vd));

  // copy from array a to vector vd:
  // now vd already contains four elements, so this new copy doesn't need to
  // create elements, we just overwrite the existing ones.
  std::copy(a, a+4, vd.begin());

  // C++11 only: Define a `std::array`:
  std::array<int, 4> sa = { 9, 10, 11, 12 };

  // create a copy:
  std::array<int, 4> sb = sa;

  // assign the array:
  sb = sa;
}

1
Приклад memcpy помилковий; джерело та пункт призначення змінюються.
AT - студент

1
Власне, це була не єдина помилка у memcpyприкладі; розмір також був помилковим. Зараз я це виправив, дякую.
celtschk

чому ви постійно пишете std, а не просто використовуєте простір імен std ???
Чорний

ви не можете зробити memcpy (b, a, sizeof a); теж?
Роді

Масив Java більше схожий, std:arrayніж подібний std::vector, оскільки має фіксований розмір.
Барт ван Хойкелом,

17

Ви можете використовувати memcpy(),

void * memcpy ( void * destination, const void * source, size_t num );

memcpy()копіює значення numбайтів з місця, на яке вказує sourceбезпосередньо, в блок пам'яті, вказаний destination.

Якщо destinationі sourceзбігаються, то можна використовувати memmove().

void * memmove ( void * destination, const void * source, size_t num );

memmove()копіює значення numбайтів з місця, на яке вказує, sourceу блок пам'яті, на який вказує destination. Копіювання відбувається так, ніби використовується проміжний буфер, що дозволяє пункту призначення та джерелу перекриватися.


3
Тут доведеться -1. OP спеціально просить рішення C ++, і ця відповідь нічого не говорить про ситуації, в яких memcpyнеправильно, тобто копіювання байтів є недостатнім.
Ed S.

2
@EdS. Якщо ви цього не помітили, OP зараз запитує рішення C або C ++.
аутист

4
Коли я відповів, ОП просив рішення C / C ++, хоча я особисто вважаю, що "C / C ++" є образливим для обох мов. :)
Deepu

досить чесно, я не розумів, що це змінюється. Можливо, це навіть говорило раніше, і я пропустив це. -1 вилучено.
Ed S.

2
@EdS Я думав, що це було 2 хвилини, але незалежно від того, на момент публікації цієї відповіді питання стосувалося як С, так і С ++. Навіть якщо я помилявся, і питання в якийсь момент говорило лише про C ++, голосування проти не було виправданим.
Jim Balter

16

Використовувати memcpyв C, std::copyв C ++.


Для невеликого масиву я припускаю, що жоден із них не спричиняє жодних накладних викликів функції ( memcpyповинен бути властивим компілятору)?
wcochran

@Mehrdad Я не сказав інакше; просто коментуючи. І я теж не проти.
MD XF

12

Мені подобається відповідь Еда С., але це працює лише для масивів фіксованого розміру, а не тоді, коли масиви визначені як покажчики.

Отже, рішення С ++, де масиви визначаються як покажчики:

#include<algorithm>
...
const int bufferSize = 10;
char* origArray, newArray;
std::copy(origArray, origArray + bufferSize, newArray);

Примітка : Не потрібно вираховувати buffersizeз 1:

  1. Копіює всі елементи в діапазоні [перший, останній), починаючи з першого і закінчуючи останнім - 1

Див .: https://en.cppreference.com/w/cpp/algorithm/copy


10

У C ви можете використовувати memcpy. У C ++ використання std::copyіз <algorithm>заголовка.


3

в C ++ 11 ви можете використовувати, Copy()що працює для контейнерів std

template <typename Container1, typename Container2>
auto Copy(Container1& c1, Container2& c2)
    -> decltype(c2.begin())
{
    auto it1 = std::begin(c1);
    auto it2 = std::begin(c2);

    while (it1 != std::end(c1)) {
        *it2++ = *it1++;
    }
    return it2;
}

Було б кращою ідеєю витягнути std::endцикл із міркувань продуктивності (c1 не змінює і не робить ітератори ітераторами протягом циклу, тому непотрібно перераховувати кінець).
celtschk

3

Я наводжу тут 2 способи впоратися з масивом для мови C та C ++. memcpy та скопіюйте обидва ar, які можна використовувати на C ++, але копіювати не можна для C, вам доведеться використовувати memcpy, якщо ви намагаєтесь скопіювати масив у C.

#include <stdio.h>
#include <iostream>
#include <algorithm> // for using copy (library function)
#include <string.h> // for using memcpy (library function)


int main(){

    int arr[] = {1, 1, 2, 2, 3, 3};
    int brr[100];

    int len = sizeof(arr)/sizeof(*arr); // finding size of arr (array)

    std:: copy(arr, arr+len, brr); // which will work on C++ only (you have to use #include <algorithm>
    memcpy(brr, arr, len*(sizeof(int))); // which will work on both C and C++

    for(int i=0; i<len; i++){ // Printing brr (array).
        std:: cout << brr[i] << " ";
    }

    return 0;
}

4
using namespace std;це погана практика . Ніколи не використовуйте його. Замість cplusplus.com використовуйте cppreference.com, який включає набагато кращу та сучаснішу документацію стандарту. stdio.hЕквівалент в C ++ є cstdio, використовувати замість. Крім того, код є досить неідіоматичним C ++. Я думаю, це було б набагато зрозуміліше, якби ви продемонстрували окремі рішення для C та C ++.
тембр

3

Просто включіть у свій код стандартну бібліотеку.

#include<algorithm>

Розмір масиву буде позначатися як n

Ваш старий масив

int oldArray[n]={10,20,30,40,50};

Заявіть новий масив, в якому вам потрібно скопіювати ваше старе значення масиву

int newArray[n];

Використовуй це

copy_n(oldArray,n,newArray);

1

По-перше, оскільки ви переходите на C ++, вектор рекомендується використовувати замість традиційного масиву . Крім того, щоб скопіювати масив або вектор,std::copy - найкращий вибір для вас.

Відвідайте цю сторінку, щоб дізнатися, як користуватися функцією копіювання: http://en.cppreference.com/w/cpp/algorithm/copy

Приклад:

std::vector<int> source_vector;
source_vector.push_back(1);
source_vector.push_back(2);
source_vector.push_back(3);
std::vector<int> dest_vector(source_vector.size());
std::copy(source_vector.begin(), source_vector.end(), dest_vector.begin());
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.