มีฟังก์ชันคัดลอกอาร์เรย์ใน C / C ++ หรือไม่?


93

ฉันเป็นโปรแกรมเมอร์ Java ที่เรียนรู้ C / C ++ ฉันจึงรู้ว่า Java มีฟังก์ชันเหมือน System.arraycopy (); เพื่อคัดลอกอาร์เรย์ ฉันสงสัยว่ามีฟังก์ชันใน C หรือ C ++ เพื่อคัดลอกอาร์เรย์หรือไม่ ฉันสามารถค้นหาการใช้งานเพื่อคัดลอกอาร์เรย์โดยใช้สำหรับลูปพอยน์เตอร์ ฯลฯ เท่านั้น มีฟังก์ชันที่ฉันสามารถใช้เพื่อคัดลอกอาร์เรย์ได้หรือไม่?


7
man memmoveและman memcpy
Tim Cooper

28
ไม่ใช้memcpyใช้std::copy. หากประเภทของคุณมีตัวสร้างสำเนาที่มีความหมายก็memcpyจะทำสิ่งที่ผิด
Ed S.

10
คุณพยายามเรียนรู้ C และ C ++ ในเวลาเดียวกันหรือไม่? พวกเขาเป็นภาษาที่แตกต่างกันมาก
Ferruccio

1
ฉันได้เรียนรู้ C นิดหน่อยและตอนนี้ฉันเพิ่งเริ่มเรียนรู้ C ++ จากสิ่งที่ฉันอ่านจากแหล่งข้อมูลออนไลน์ฉันคิดว่า C ++ เป็นเพียงภาษาที่มีคุณสมบัติเพิ่มเติมมากมายสำหรับภาษา C
JL

6
ฉันพูดแบบนี้เพราะไม่มีใครพูดถึงมาก่อน: ใน C ++ คุณควรใช้ std :: vector ในเกือบทุกกรณี มีหลายกรณีที่คอนเทนเนอร์อื่น ๆ ก็มีประโยชน์เช่นกัน แต่กรณีส่วนใหญ่ std :: vector จะเป็นตัวเลือกที่ดีที่สุด อย่าใช้อาร์เรย์ดิบใน C ++ และพยายามหลีกเลี่ยง std :: array เว้นแต่ว่าจำเป็น
Skalli

คำตอบ:


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

@Aaron_Lee: ฉันเพิ่งทดสอบและคัดลอกองค์ประกอบไปยังอาร์เรย์ในตำแหน่งหน่วยความจำแยกต่างหาก เห็นได้ชัดว่าคลาสอาร์เรย์มีโอเวอร์โหลดของตัวเองสำหรับตัวดำเนินการกำหนด
Dave Rove

5
พวกคุณคงทราบดีว่าไม่มีตัวดำเนินการกำหนดปรากฏในโค้ดสองบรรทัดนี้ใช่ไหม? นั่นคือตัวสร้างการคัดลอกที่ถูกเรียกแม้ว่าสัญกรณ์จะดูเหมือนตัวดำเนินการกำหนด
Albino Cordeiro

143

เนื่องจากคุณขอโซลูชัน 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'
David 天宇 Wong

23
@David 天宇 Wong: คุณกำลังใช้คอมไพเลอร์เก่าหรือคุณไม่ได้ใส่ส่วนหัวไว้ อยู่ใน<iterator>
Ed S.

9
บางทีคุณควรบอกว่าคุณต้องการอะไรด้วย เป็นสำเนาใน<algorithm>?
Jerry Jeremiah

17
ฉันถามเพียงเพราะถ้าคุณต้องอธิบายว่า std :: begin อยู่ใน <iterator> นั่นหมายความว่าผู้คนไม่ได้ googling std :: เริ่มค้นหาว่ามันอยู่ในส่วนหัวใดดังนั้นพวกเขาจึงไม่น่าจะใช้ google std :: copy เหมือนกัน เหตุผล. จะให้คำตอบที่ดีกว่าหากไม่มีใครต้องถามสิ่งที่ตอบเฉพาะในความคิดเห็น บางทีฉันควรจะแก้ไขคำตอบแทนที่จะแจ้งให้คุณทำ
Jerry Jeremiah

3
คุณสามารถเปลี่ยน start (src) เป็น src และ end (src) เป็น src + arr_size
Calvin

83

เป็นคนอื่นได้กล่าวถึงใน C memcpyคุณจะใช้ อย่างไรก็ตามโปรดทราบว่านี่เป็นการคัดลอกหน่วยความจำดิบดังนั้นหากโครงสร้างข้อมูลของคุณมีตัวชี้ถึงตัวเองหรือถึงกันตัวชี้ในสำเนาจะยังคงชี้ไปที่วัตถุดั้งเดิม

ใน C ++ คุณยังสามารถใช้memcpyถ้าสมาชิกอาร์เรย์ของคุณเป็น POD (นั่นคือโดยพื้นฐานแล้วประเภทที่คุณสามารถใช้ได้โดยไม่เปลี่ยนแปลงใน C) แต่โดยทั่วไปmemcpyจะไม่ได้รับอนุญาต std::copyในฐานะที่เป็นคนพูดถึงฟังก์ชั่นในการใช้งาน

ต้องบอกว่าใน C ++ คุณไม่ค่อยควรใช้อาร์เรย์ดิบ คุณควรใช้คอนเทนเนอร์มาตรฐานแทน ( std::vectorซึ่งใกล้เคียงที่สุดกับอาร์เรย์ในตัวและฉันคิดว่าใกล้เคียงกับอาร์เรย์ Java มากที่สุด - ใกล้กว่าอาร์เรย์ C ++ ธรรมดาแน่นอน - แต่std::dequeหรือstd::listอาจเหมาะสมกว่าในบางกรณี) หรือถ้าคุณใช้ C ++ 11 std::arrayซึ่งอยู่ใกล้กับอาร์เรย์ในตัวมาก แต่มีค่าความหมายเหมือนกับ C ++ ประเภทอื่น ๆ ทุกประเภทที่ฉันกล่าวถึงที่นี่สามารถคัดลอกได้โดยการมอบหมายงานหรือคัดลอกโครงสร้าง ยิ่งไปกว่านั้นคุณสามารถ "cross-copy" จาก 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); เกินไป?
rodi

อาร์เรย์ Java เป็นstd:arrayมากกว่า like std::vectorเนื่องจากมีขนาดคงที่
Bart van Heukelom

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
@ เอดเอส. ในกรณีที่คุณไม่สังเกตเห็น OP กำลังขอโซลูชันC หรือ C ++
ออทิสติก

4
เมื่อฉันตอบ OP กำลังขอโซลูชัน C / C ++ แม้ว่าโดยส่วนตัวแล้วฉันเชื่อว่า "C / C ++" เป็นการดูถูกทั้งสองภาษา :)
Deepu

พอใช้ฉันไม่รู้ว่ามันกำลังเปลี่ยนแปลง บางทีมันอาจจะบอกว่าก่อนหน้านี้และฉันพลาดมัน -1 ลบ
Ed S.

2
@EdS ฉันคิดว่ามันเป็นเวลา 2 นาที แต่ไม่ว่าในขณะที่คำตอบนี้ถูกโพสต์คำถามที่อ้างถึงทั้ง C และ C ++ แม้ว่าฉันจะผิดและในบางคำถามก็พูดเฉพาะ C ++ แต่การโหวตลดก็ไม่รับประกัน
Jim Balter

16

ใช้memcpyใน C std::copyใน C ++


สำหรับอาร์เรย์ขนาดเล็กฉันถือว่าไม่มีค่าใช้จ่ายในการเรียกฟังก์ชันใด ๆ ( memcpyควรเป็นคอมไพเลอร์ที่อยู่ภายใน)?
wcochran

@Mehrdad ฉันไม่ได้พูดอย่างอื่น; เพียงแค่แสดงความคิดเห็น และฉันก็ไม่ได้ลงคะแนนด้วยเช่นกัน
MD XF

12

ฉันชอบคำตอบของ Ed S. แต่ใช้ได้กับอาร์เรย์ขนาดคงที่เท่านั้นและไม่ใช่เมื่ออาร์เรย์ถูกกำหนดให้เป็นพอยน์เตอร์

ดังนั้นโซลูชัน C ++ ที่อาร์เรย์ถูกกำหนดให้เป็นพอยน์เตอร์:

#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



3

ใน C ++ 11 คุณสามารถใช้Copy()งานได้กับคอนเทนเนอร์มาตรฐาน

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 ++
tambre

3

เพียงรวมไลบรารีมาตรฐานไว้ในโค้ดของคุณ

#include<algorithm>

ขนาดอาร์เรย์จะแสดงเป็น n

อาร์เรย์เก่าของคุณ

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

ประกาศ New Array ซึ่งคุณต้องคัดลอกค่าอาร์เรย์เก่าของคุณ

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());
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.