C / C ++ 'da bir diziyi kopyalamak için bir işlev var mı?


92

Ben C / C ++ öğrenen bir Java programcısıyım. Yani Java'nın System.arraycopy () gibi bir işlevi olduğunu biliyorum; bir diziyi kopyalamak için. Bir diziyi kopyalamak için C veya C ++ 'da bir işlev olup olmadığını merak ediyordum. Sadece for döngüsü, işaretçiler vb. Kullanarak bir diziyi kopyalamak için bir uygulama bulabildim. Bir diziyi kopyalamak için kullanabileceğim bir işlev var mı?


7
man memmoveveman memcpy
Tim Cooper

28
Kullanmayın memcpy, kullanın std::copy. Türünüzün anlamlı bir kopya kurucusu varsa memcpy, yanlış olanı yapacaktır.
Ed S.

10
Aynı anda C ve C ++ öğrenmeye mi çalışıyorsunuz? Çok farklı diller.
Ferruccio

1
Biraz C öğrendim ve şimdi son zamanlarda C ++ öğrenmeye başladım. Çevrimiçi bir kaynaktan okuduğuma göre, C ++ 'nın C diline pek çok ek özelliği olan bir dil olduğunu düşündüm.
JL

6
Bunu söylüyorum çünkü daha önce kimse bundan bahsetmedi: C ++ 'da hemen hemen her durumda std :: vector kullanmalısınız. Diğer kapların da yararlı olduğu durumlar vardır, ancak çoğu durumda std :: vector en iyi seçenek olacaktır. C ++ 'da ham diziler kullanmayın ve gerekli olmadıkça std :: diziden kaçınmaya çalışın.
Skalli

Yanıtlar:


79

C ++ 11'den beri, dizileri doğrudan şu şekilde kopyalayabilirsiniz std::array:

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

İşte std :: array ile ilgili dokümantasyon


@XAleXOwnZX: Kopyalama atamasını destekleyen diğer türlerle aynı. B = A.
swalog

2
Sanırım işlev A'nın bellek adresini B'ye kopyala. A'nın öğe değerlerini B'nin bellek adresini değiştirmeden B'ye kopyalamaya çalışırsam. Bunu nasıl yapabilirim?
Aaron Lee

@Aaron_Lee: Biraz önce test ettim ve öğeleri gerçekten ayrı bir bellek konumundaki bir diziye kopyalıyor. Dizi sınıfının, atama operatörü için kendi aşırı yüklemesi olduğu açıktır.
Dave Rove

4
Bu iki kod satırında hiçbir atama operatörünün görünmediğinin farkındasınız, değil mi? Bu, gösterim atama operatörüne benzese bile çağrılan kopya yapıcısıdır.
Albino Cordeiro

139

Bir C ++ çözümü istediğiniz için ...

#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' üyesi değil
David 天宇 Wong

23
@David 天宇 Wong: Eski bir derleyici kullanıyorsunuz veya başlığı eklemediniz. İçinde<iterator>
Ed S.

9
Belki hangisine ihtiyacın olduğunu söylemelisin. Kopya mı var <algorithm>?
Jerry Jeremiah

15
Sadece std :: begin'ın <iterator> içinde olduğunu açıklamak zorunda olsaydınız bu, insanların googling yapmadığı anlamına gelir std :: hangi başlıkta olduğunu bulmaya başlarlar, bu yüzden aynı şekilde google std :: copy yapmaları olası değildir sebep. Kimsenin yalnızca yorumlarda yanıtlanan soruları sorması gerekmiyorsa, daha iyi bir yanıt verir. Belki senden yapmanı istemek yerine cevabı düzenlemeliydim.
Jerry Jeremiah

3
begin (src) yi src ve end (src) yi src + arr_size olarak değiştirebilirsiniz
Calvin

82

Başkalarının da bahsettiği gibi, C'de kullanırsınız memcpy. Bununla birlikte, bunun bir ham bellek kopyası yaptığına dikkat edin, bu nedenle veri yapılarınız kendilerine veya birbirlerine göstericiye sahipse, kopyadaki işaretçiler yine de orijinal nesneleri gösterecektir.

C ++ da kullanabilirsiniz memcpydiziniz üyeleri, (ayrıca C değişmeden kullanmış olabilir, esasen türleri) ama genel olarak POD ise memcpyedecektir değil izin verilebilir. Diğerlerinde belirtildiği gibi, kullanılacak işlev std::copy.

Bunu söyledikten sonra, C ++ 'da nadiren ham dizileri kullanmalısınız. Bunun yerine ya standart konteynerlerin birini kullanmalıdır ( std::vectorbir dizide dahili ve ayrıca Java diziler en yakın düşünmek en yakın - yakın düz C'nin ++ diziler, gerçekten de - ama std::dequeya std::listbazı durumlarda daha uygun olabilir) veya std::arrayyerleşik dizilere çok yakın olan, ancak diğer C ++ türleri gibi değer semantiği olan C ++ 11 kullanıyorsanız . Burada bahsettiğim tüm türler ödev veya kopya oluşturma yoluyla kopyalanabilir. Dahası, yineleyici sözdizimini kullanarak opne'den diğerine (ve hatta yerleşik bir diziden) "çapraz kopyalama" yapabilirsiniz.

Bu, olasılıklara genel bir bakış sağlar (ilgili tüm başlıkların dahil edildiğini varsayıyorum):

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 örneği yanlıştır; kaynak ve hedef değiştirilir.
AT - öğrenci

1
Aslında, memcpyörnekteki tek hata bu değildi ; boyut da yanlıştı. Şimdi düzelttim, teşekkürler.
celtschk

neden std'nin isim alanını kullanmak yerine her zaman std yazıyorsunuz ???
Siyah

memcpy yapamaz mısın (b, a, sizeof a); çok?
rodi

Bir Java dizisi sabit bir boyuta sahip olduğu için benzerden std:arrayçok gibidir std::vector.
Bart van Heukelom

17

Sen kullanabilirsiniz memcpy(),

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

memcpy()numbaytların değerlerini, ile gösterilen konumdan sourcedoğrudan işaret ettiği bellek bloğuna kopyalar destination.

Eğer destinationve sourceörtüşme, o zaman kullanabilirsiniz memmove().

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

memmove()numbaytların değerlerini, ile gösterilen konumdan işaret ettiği sourcebellek bloğuna kopyalar destination. Kopyalama, bir ara tampon kullanılmış gibi gerçekleşir ve hedef ve kaynağın çakışmasına izin verir.


3
Burada -1 olması gerekecek. OP, özellikle bir C ++ çözümü istiyor ve bu yanıt memcpy, yanlış olan durumlarla ilgili hiçbir şey söylemiyor , yani baytları kopyalamanın yetersiz olduğu.
Ed S.

2
@EdS. Fark etmediyseniz, OP şimdi bir C veya C ++ çözümü istiyor .
otistik

4
OP'ye cevap verdiğimde C / C ++ çözümlerini soruyordum, ancak kişisel olarak "C / C ++" ın her iki dile de hakaret olduğuna inanıyorum. :)
Deepu

yeterince adil, bunun değiştiğinin farkında değildim. Belki daha önce söyledi ve ben özledim. -1 kaldırıldı.
Ed S.

2
@EdS 2 dakika olduğunu düşünmüştüm, ama ne olursa olsun, bu cevabın gönderildiği sırada soru hem C hem de C ++ ile ilgili. Yanılıyorsam ve soru bir noktada sadece C ++ dediğinde, olumsuz oylama garanti edilmedi.
Jim Balter

16

memcpyC, std::copyC ++ 'da kullanın .


Küçük bir dizi için, herhangi bir fonksiyon çağrısı ek yüküne maruz kalmadığını varsayıyorum ( memcpybir derleyici içsel olmalıdır)?
wcochran

@Mehrdad Ben aksini söylemedim; sadece bir yorum yapıyorum. Ben de olumsuz oy vermedim.
MD XF

12

Ed S.'nin cevabını beğendim, ancak bu yalnızca sabit boyutlu diziler için işe yarıyor ve diziler işaretçi olarak tanımlandığında değil.

Yani dizilerin işaretçiler olarak tanımlandığı C ++ çözümü:

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

Not : buffersize1 ile düşmeye gerek yok :

  1. [İlk, son) aralıktaki tüm öğeleri ilkinden başlayıp sonuncuya kadar kopyalar - 1

Bakınız: https://en.cppreference.com/w/cpp/algorithm/copy


10

C'de kullanabilirsiniz memcpy. C ++ std::copy'da <algorithm>başlıktan kullanın .


3

C ++ 11'de Copy()std kapsayıcılar için çalışan kullanabilirsiniz

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::endPerformans nedenleriyle döngüden çıkmak daha iyi bir fikir olabilir (c1 döngü sırasında yineleyicileri değiştirmez veya geçersiz kılmaz, bu nedenle sonu yeniden hesaplamak gereksizdir).
celtschk

3

Burada C ve C ++ dili için dizi başa çıkmanın 2 yolunu veriyorum. memcpy ve copy, her ikisi de C ++ 'da kullanılabilir, ancak copy C için kullanılamaz, C dizisini kopyalamaya çalışıyorsanız memcpy kullanmanız gerekir .

#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;kötü bir uygulamadır . Onu asla kullanma. Cplusplus.com yerine, standardın çok daha iyi ve güncel dokümantasyonunu içeren cppreference.com'u kullanın. stdio.hC ++ eşdeğer cstdiokullanımı yerine,. Ek olarak, kod oldukça deyimsel olmayan C ++ 'dır. Bence C ve C ++ için ayrı çözümler göstermiş olsaydınız çok daha net olurdu.
tambre

3

Standart kitaplığı kodunuza eklemeniz yeterlidir.

#include<algorithm>

Dizi boyutu şu şekilde belirtilecektir: n

Eski Diziniz

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

Eski dizi değerinizi kopyalamanız gereken Yeni Dizi Bildirin

int newArray[n];

Bunu kullan

copy_n(oldArray,n,newArray);

1

Öncelikle, C ++ 'ya geçtiğiniz için geleneksel dizi yerine vektör kullanılması önerilir . Ayrıca, bir dizi veya vektörü kopyalamak std::copysizin için en iyi seçimdir.

Kopyalama işlevini nasıl kullanacağınızı öğrenmek için bu sayfayı ziyaret edin: http://en.cppreference.com/w/cpp/algorithm/copy

Misal:

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());
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.