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.