Có một chức năng để sao chép một mảng trong C / C ++ không?


91

Tôi là một lập trình viên Java đang học C / C ++. Vì vậy, tôi biết rằng Java có một chức năng như System.arraycopy (); để sao chép một mảng. Tôi đã tự hỏi nếu có một hàm trong C hoặc C ++ để sao chép một mảng. Tôi chỉ có thể tìm thấy triển khai để sao chép một mảng bằng cách sử dụng vòng lặp for, con trỏ, v.v. Có chức năng nào mà tôi có thể sử dụng để sao chép một mảng không?


7
man memmoveman memcpy
Tim Cooper

28
Không sử dụng memcpy, sử dụng std::copy. Nếu kiểu của bạn có một hàm tạo bản sao có ý nghĩa thì memcpysẽ làm sai.
Ed S.

10
Bạn thực sự đang cố gắng học C và C ++ cùng một lúc? Chúng là những ngôn ngữ rất khác nhau.
Ferruccio

1
Tôi đã học một chút về C và bây giờ tôi mới bắt đầu học C ++. Từ những gì tôi đọc được từ một tài nguyên trực tuyến, tôi nghĩ C ++ chỉ là một ngôn ngữ có rất nhiều tính năng bổ sung cho ngôn ngữ C.
JL

6
Tôi đang nói điều này bởi vì chưa ai đề cập đến nó trước đây: Trong C ++, bạn nên sử dụng std :: vector trong hầu hết các trường hợp. Có những trường hợp các vùng chứa khác cũng hữu ích, nhưng tôi hầu hết các trường hợp std :: vector sẽ là lựa chọn tốt nhất. Không sử dụng mảng thô trong C ++ và cố gắng tránh std :: array trừ khi cần thiết.
Skalli

Câu trả lời:


79

Kể từ C ++ 11, bạn có thể sao chép mảng trực tiếp với std::array:

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

Đây là tài liệu về std :: array


@XAleXOwnZX: Giống với bất kỳ loại nào khác hỗ trợ gán sao chép. B = A.
swalog

2
Tôi nghĩ rằng chức năng là sao chép địa chỉ bộ nhớ của A sang B. Nếu tôi cố gắng sao chép các giá trị mục của A sang B mà không thay đổi địa chỉ bộ nhớ của B. Làm thế nào tôi có thể làm điều đó?
Aaron Lee,

@Aaron_Lee: Tôi vừa thử nghiệm nó và nó sao chép chính xác các phần tử vào một mảng trong một vị trí bộ nhớ riêng biệt. Lớp mảng rõ ràng có quá tải riêng cho toán tử gán.
Dave Rove

4
Các bạn nhận ra rằng không có toán tử gán nào xuất hiện trong hai dòng mã đó, phải không? Đó là hàm tạo bản sao đang được gọi mặc dù ký hiệu trông giống như toán tử gán.
Albino Cordeiro

138

Vì bạn đã yêu cầu giải pháp 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' không phải là thành viên của 'std'
David 天宇 Wong

23
@David 天宇 Wong: Bạn đang sử dụng trình biên dịch cũ hoặc bạn không bao gồm tiêu đề. Nó trong<iterator>
Ed S.

9
Có lẽ bạn nên nói cái nào bạn cần. Có sao chép trong <algorithm>không?
Jerry Jeremiah

15
Tôi chỉ hỏi vì nếu bạn phải giải thích rằng std :: begin nằm trong <iterator>, điều đó có nghĩa là mọi người không googling std :: begin để tìm hiểu tiêu đề của nó nên họ không chắc sẽ google std :: copy cho giống nhau lý do. Nó tạo ra một câu trả lời tốt hơn nếu không ai phải hỏi những thứ chỉ được trả lời trong các bình luận. Có lẽ tôi nên chỉnh sửa câu trả lời thay vì nhắc bạn làm điều đó.
Jerry Jeremiah

3
bạn có thể thay đổi bắt đầu (src) vào src và kết thúc (src) vào src + arr_size
Calvin

82

Như những người khác đã đề cập, trong C bạn sẽ sử dụng memcpy. Tuy nhiên, lưu ý rằng điều này thực hiện một bản sao bộ nhớ thô, vì vậy nếu cấu trúc dữ liệu của bạn có con trỏ tới chính chúng hoặc với nhau, các con trỏ trong bản sao sẽ vẫn trỏ đến các đối tượng gốc.

Trong C ++, bạn cũng có thể sử dụng memcpynếu các thành viên mảng của bạn là POD (nghĩa là về cơ bản các kiểu mà bạn cũng có thể sử dụng không thay đổi trong C), nhưng nói chung, memcpysẽ không được phép. Như những người khác đã đề cập, chức năng sử dụng là std::copy.

Phải nói rằng, trong C ++, bạn hiếm khi nên sử dụng mảng thô. Thay vào đó, bạn nên sử dụng một trong các vùng chứa tiêu chuẩn ( std::vectorlà vùng gần nhất với mảng tích hợp sẵn và tôi cũng nghĩ là gần nhất với mảng Java - thực sự gần hơn so với mảng C ++ thuần túy - nhưng std::dequehoặc std::listcó thể thích hợp hơn trong một số trường hợp) hoặc, nếu bạn sử dụng C ++ 11, std::arrayrất gần với các mảng dựng sẵn, nhưng có ngữ nghĩa giá trị như các loại C ++ khác. Tất cả các loại tôi đề cập ở đây có thể được sao chép bằng cách phân công hoặc sao chép xây dựng. Hơn nữa, bạn có thể "sao chép chéo" từ opne này sang opne khác (và thậm chí từ một mảng dựng sẵn) bằng cách sử dụng cú pháp trình lặp.

Điều này cung cấp một cái nhìn tổng quan về các khả năng (tôi cho rằng tất cả các tiêu đề liên quan đã được bao gồm):

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
Ví dụ về memcpy là sai; nguồn và đích được chuyển đổi.
AT - sinh viên

1
Trên thực tế, đó không phải là sai lầm duy nhất trong memcpyví dụ; kích thước cũng sai. Bây giờ tôi đã sửa nó, cảm ơn bạn.
celtschk

tại sao bạn viết std mọi lúc thay vì chỉ sử dụng không gian tên của std ???
Đen

bạn không thể làm memcpy (b, a, sizeof a); quá?
rodi

Mảng Java giống std:arrayhơn là giống như vậy std::vector, bởi vì nó có kích thước cố định.
Bart van Heukelom

17

Bạn có thể sử dụng memcpy(),

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

memcpy()sao chép các giá trị của numbyte từ vị trí được trỏ đến sourcetrực tiếp vào khối bộ nhớ được trỏ tới destination.

Nếu destinationsourcechồng chéo, sau đó bạn có thể sử dụng memmove().

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

memmove()sao chép các giá trị của numbyte từ vị trí được trỏ sourceđến vào khối bộ nhớ được trỏ bởi destination. Việc sao chép diễn ra như thể một bộ đệm trung gian được sử dụng, cho phép đích và nguồn chồng lên nhau.


3
Phải -1 ở đây. OP đang yêu cầu cụ thể một giải pháp C ++ và câu trả lời này không nói gì về các trường hợp memcpysai, tức là sao chép byte là không đủ.
Ed S.

2
@EdS. Trong trường hợp bạn không nhận thấy, OP hiện đang yêu cầu giải pháp C hoặc C ++.
tự kỷ

4
Khi tôi trả lời OP đang yêu cầu các giải pháp C / C ++, mặc dù cá nhân tôi tin rằng "C / C ++" là sự xúc phạm đối với cả hai ngôn ngữ. :)
Deepu

công bằng mà nói, tôi không nhận ra nó đang thay đổi. Có lẽ nó thậm chí đã nói điều đó sớm hơn và tôi đã bỏ lỡ nó. -1 đã bị xóa.
Ed S.

2
@EdS Tôi nghĩ rằng đó là 2 phút, nhưng bất kể, tại thời điểm câu trả lời này được đăng, câu hỏi đề cập đến cả C và C ++. Ngay cả khi tôi đã sai và câu hỏi tại một thời điểm nào đó chỉ nói C ++, downvote không được bảo hành.
Jim Balter

16

Sử dụng memcpytrong C, std::copytrong C ++.


Đối với một mảng nhỏ, tôi giả sử không phải chịu bất kỳ chi phí gọi hàm nào ( memcpynên là một trình biên dịch nội tại)?
wcochran

@Mehrdad Tôi không nói khác; chỉ đưa ra một bình luận. Và tôi cũng không tán thành nó.
MD XF

12

Tôi thích câu trả lời của Ed S., nhưng điều này chỉ hoạt động đối với các mảng có kích thước cố định chứ không phải khi các mảng được xác định là con trỏ.

Vì vậy, giải pháp C ++ trong đó các mảng được định nghĩa là con trỏ:

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

Lưu ý : Không cần khấu trừ buffersizevới 1:

  1. Sao chép tất cả các phần tử trong phạm vi [đầu tiên, cuối cùng) bắt đầu từ đầu tiên và tiếp tục đến cuối cùng - 1

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


10

Trong C bạn có thể sử dụng memcpy. Trong C ++ sử dụng std::copytừ <algorithm>tiêu đề.


3

trong C ++ 11, bạn có thể sử dụng Copy()nó hoạt động cho các vùng chứa 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;
}

Sẽ là một ý tưởng tốt hơn nếu bạn rút std::endra khỏi vòng lặp, vì lý do hiệu suất (c1 không thay đổi hoặc làm mất hiệu lực của các trình vòng lặp trong suốt vòng lặp, vì vậy không cần thiết phải tính toán lại kết thúc).
celtschk

3

Tôi đưa ra đây 2 cách đối phó mảng, cho ngôn ngữ C và C ++. memcpysao chép cả ar đều có thể sử dụng được trên C ++ nhưng bản sao không sử dụng được đối với C, bạn phải sử dụng memcpy nếu bạn đang cố gắng sao chép mảng trong 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;là một thực hành xấu . Đừng bao giờ sử dụng nó. Thay vì cplusplus.com, vui lòng sử dụng cppreference.com, trang này bao gồm nhiều tài liệu tốt hơn và cập nhật về tiêu chuẩn. Các stdio.htương đương trong C ++ là cstdio, sử dụng thay thế. Ngoài ra, mã này là C ++ khá phi ngôn ngữ. Tôi nghĩ sẽ rõ ràng hơn nhiều nếu bạn giới thiệu các giải pháp riêng biệt cho C và C ++.
tambre

3

Chỉ cần đưa thư viện chuẩn vào mã của bạn.

#include<algorithm>

Kích thước mảng sẽ được ký hiệu là n

Mảng cũ của bạn

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

Khai báo mảng mới trong đó bạn phải sao chép giá trị mảng cũ của mình

int newArray[n];

Dùng cái này

copy_n(oldArray,n,newArray);

1

Thứ nhất, vì bạn đang chuyển sang C ++, nên sử dụng vector thay vì mảng truyền thống . Bên cạnh đó, để sao chép một mảng hoặc vector, std::copylà sự lựa chọn tốt nhất cho bạn.

Truy cập trang này để biết cách sử dụng chức năng sao chép: http://en.cppreference.com/w/cpp/algorithm/copy

Thí dụ:

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());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.