Czy istnieje funkcja do kopiowania tablicy w C / C ++?


91

Jestem programistą Java uczącym się C / C ++. Więc wiem, że Java ma funkcję taką jak System.arraycopy (); aby skopiować tablicę. Zastanawiałem się, czy w C lub C ++ jest funkcja do kopiowania tablicy. Udało mi się znaleźć tylko implementację do skopiowania tablicy za pomocą pętli for, wskaźników itp. Czy istnieje funkcja, której mogę użyć do skopiowania tablicy?


7
man memmoveiman memcpy
Tim Cooper

28
Nie używaj memcpy, używaj std::copy. Jeśli twój typ ma sensowny konstruktor kopiujący memcpy, zrobi źle.
Ed S.,

10
Czy faktycznie próbujesz uczyć się C i C ++ w tym samym czasie? To bardzo różne języki.
Ferruccio

1
Cóż, nauczyłem się trochę C, a teraz niedawno zacząłem uczyć się C ++. Z tego, co przeczytałem w zasobach online, pomyślałem, że C ++ to tylko język z wieloma dodatkowymi funkcjami do języka C.
JL

6
Mówię to, ponieważ nikt wcześniej o tym nie wspomniał: w C ++ powinieneś używać std :: vector w prawie wszystkich przypadkach. Istnieją przypadki, w których inne kontenery są również przydatne, ale w większości przypadków std :: vector będzie najlepszą opcją. Nie używaj surowych tablic w C ++ i staraj się unikać std :: array, chyba że jest to konieczne.
Skalli

Odpowiedzi:


79

Od C ++ 11 możesz kopiować tablice bezpośrednio za pomocą std::array:

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

Oto dokumentacja dotycząca std :: array


@XAleXOwnZX: To samo, co każdy inny typ, który obsługuje przypisywanie kopii. B = A.
swalog

2
Myślę, że funkcja polega na skopiowaniu adresu pamięci A do B. Jeśli spróbuję skopiować wartości pozycji A do B bez zmiany adresu pamięci B. Jak mogę to zrobić?
Aaron Lee

@Aaron_Lee: Właśnie to przetestowałem i naprawdę kopiuje elementy do tablicy w oddzielnym miejscu w pamięci. Klasa tablicy ewidentnie ma własne przeciążenie dla operatora przypisania.
Dave Rove

4
Zdajecie sobie sprawę, że w tych dwóch wierszach kodu nie ma operatorów przypisania, prawda? To jest konstruktor kopiujący, który jest wywoływany, mimo że notacja wygląda jak operator przypisania.
Albino Cordeiro

138

Ponieważ poprosiłeś o rozwiązanie w 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' nie należy do 'std'
David 天宇 Wong

23
@David 天宇 Wong: Używasz starego kompilatora lub nie dołączyłeś nagłówka. Jest<iterator>
Ed S.

9
Może powinieneś powiedzieć, który obejmuje, czego potrzebujesz. Czy jest kopia <algorithm>?
Jerry Jeremiah

15
Pytam tylko dlatego, że gdybyś musiał wyjaśnić, że std :: begin było w <iterator>, co oznacza, że ​​ludzie nie szukają w Google std :: zacznij dowiadywać się, w jakim jest nagłówku, więc jest mało prawdopodobne, aby wyszukali w Google std :: copy dla tego samego powód. Lepszą odpowiedzią jest, jeśli nikt nie musi pytać o rzeczy, na które odpowiedzi udzielają tylko komentarze. Może powinienem był po prostu zredagować odpowiedź, zamiast zachęcać Cię do tego.
Jerry Jeremiah

3
możesz zmienić begin (src) na src i end (src) na src + arr_size
Calvin

82

Jak wspominali inni, w C użyjesz memcpy. Należy jednak pamiętać, że powoduje to wykonanie surowej kopii pamięci, więc jeśli struktury danych mają wskaźnik do siebie lub do siebie nawzajem, wskaźniki w kopii nadal będą wskazywać na oryginalne obiekty.

W C ++ można również użyć memcpy, jeśli członkowie tablicy są POD (czyli zasadniczo typy, które można również użyte niezmienione w C), ale w ogóle, memcpybędzie nie być dozwolone. Jak wspominali inni, funkcja do użycia to std::copy.

Powiedziawszy to, w C ++ rzadko powinieneś używać surowych tablic. Zamiast tego powinieneś albo użyć jednego ze standardowych kontenerów ( std::vectorjest najbliższy wbudowanej tablicy, a także myślę, że najbliższy tablicom Java - rzeczywiście bliżej niż zwykłe tablice C ++ - ale std::dequelub std::listmoże być bardziej odpowiedni w niektórych przypadkach) lub, jeśli używasz C ++ 11, std::arrayktóry jest bardzo zbliżony do tablic wbudowanych, ale z semantyką wartości, podobnie jak inne typy C ++. Wszystkie typy, o których tutaj wspomniałem, można skopiować przez przypisanie lub konstrukcję kopii. Co więcej, możesz "cross-copy" z opne do innego (a nawet z wbudowanej tablicy) używając składni iteratora.

Daje to przegląd możliwości (zakładam, że uwzględniono wszystkie odpowiednie nagłówki):

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
Przykład memcpy jest błędny; źródło i miejsce docelowe są przełączane.
AT - student

1
Właściwie to nie był jedyny błąd w tym memcpyprzykładzie; rozmiar również był zły. Teraz to naprawiłem, dziękuję.
celtschk

dlaczego cały czas piszesz std zamiast po prostu używać przestrzeni nazw std ???
Czarny

nie możesz zrobić memcpy (b, a, sizeof a); też?
rodi

Tablica Java jest bardziej std:arrayniż podobna std::vector, ponieważ ma stały rozmiar.
Bart van Heukelom

17

Możesz użyć memcpy(),

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

memcpy()kopiuje wartości numbajtów z lokalizacji wskazywanej przez sourcebezpośrednio do bloku pamięci wskazywanego przez destination.

Jeśli destinationi sourcenakładają się, możesz użyć memmove().

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

memmove()kopiuje wartości numbajtów z lokalizacji wskazywanej przez sourcedo bloku pamięci wskazywanego przez destination. Kopiowanie odbywa się tak, jakby był używany bufor pośredni, dzięki czemu miejsce docelowe i źródło nakładają się.


3
Muszę tutaj -1. OP prosi o rozwiązanie w C ++, a ta odpowiedź nie mówi nic o sytuacjach, w których memcpyjest źle, tj. Kopiowanie bajtów jest niewystarczające.
Ed S.,

2
@EdS. Jeśli nie zauważyłeś, OP prosi teraz o rozwiązanie w C lub C ++.
autystyczny

4
Kiedy odpowiedziałem, OP prosił o rozwiązania C / C ++, chociaż osobiście uważam, że „C / C ++” jest obrazą dla obu języków. :)
Deepu

w porządku, nie zdawałem sobie sprawy, że to się zmienia. Może nawet powiedział to wcześniej i przegapiłem to. -1 usunięte.
Ed S.,

2
@EdS Myślałem, że to 2 minuty, ale niezależnie od tego, w momencie zamieszczania tej odpowiedzi pytanie dotyczyło zarówno C, jak i C ++. Nawet jeśli się myliłem, a pytanie w pewnym momencie brzmiało tylko C ++, głos przeciw nie był uzasadniony.
Jim Balter

16

Użyj memcpyw C, std::copyw C ++.


W przypadku małej tablicy zakładam, że nie ponosimy żadnego narzutu wywołania funkcji ( memcpypowinien być wewnętrzny kompilator)?
wcochran

@Mehrdad Nie powiedziałem inaczej; tylko komentuję. I nie przegłosowałem tego.
MD XF

12

Podoba mi się odpowiedź Eda S., ale działa to tylko w przypadku tablic o stałym rozmiarze, a nie wtedy, gdy tablice są zdefiniowane jako wskaźniki.

Tak więc rozwiązanie C ++, w którym tablice są zdefiniowane jako wskaźniki:

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

Uwaga : nie ma potrzeby odejmowania za buffersizepomocą 1:

  1. Kopiuje wszystkie elementy z zakresu [pierwszy, ostatni] zaczynając od pierwszego i przechodząc do ostatniego - 1

Zobacz: https://en.cppreference.com/w/cpp/algorithm/copy



3

w C ++ 11 możesz użyć Copy()tego, co działa dla kontenerów 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;
}

Lepszym pomysłem byłoby wyciągnięcie std::endpętli z pętli ze względu na wydajność (c1 nie zmienia ani nie unieważnia iteratorów podczas pętli, więc nie jest konieczne ponowne obliczanie końca).
celtschk,

3

Podaję tutaj 2 sposoby radzenia sobie z tablicą, dla języka C i C ++. memcpy i kopiuj oba ar użyteczne w C ++, ale kopiowanie nie jest użyteczne dla C, musisz użyć memcpy, jeśli próbujesz skopiować tablicę w 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;to zła praktyka . Nigdy go nie używaj. Zamiast cplusplus.com prosimy o skorzystanie z cppreference.com, która zawiera znacznie lepszą i aktualną dokumentację standardu. stdio.hOdpowiednik w C ++ jest cstdio, że stosowanie zamiast. Ponadto kod jest dość nieidiomatyczny w C ++. Myślę, że byłoby znacznie jaśniej, gdybyś zaprezentował oddzielne rozwiązania dla C i C ++.
tambre

3

Po prostu dołącz standardową bibliotekę do swojego kodu.

#include<algorithm>

Rozmiar tablicy będzie oznaczony jako n

Twój stary Array

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

Zadeklaruj nową tablicę, w której musisz skopiować starą wartość tablicy

int newArray[n];

Użyj tego

copy_n(oldArray,n,newArray);

1

Po pierwsze, ponieważ przechodzisz na C ++, zaleca się używanie wektora zamiast tradycyjnej tablicy . Poza tym, aby skopiować tablicę lub wektor,std::copy jest najlepszym wyborem dla Ciebie.

Odwiedź tę stronę, aby dowiedzieć się, jak korzystać z funkcji kopiowania: http://en.cppreference.com/w/cpp/algorithm/copy

Przykład:

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());
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.