在C/C++中是否有一个复制数组的函数?

132

我知道Java有一个函数System.arraycopy();可以复制一个数组。我想知道C或C++中是否有一个函数可以复制一个数组。我只能找到使用for循环、指针等来实现复制数组的方法。但是是否有一个库函数可以用来复制数组呢?


8
man memmoveman memcpy这两个命令是C语言中用来移动内存块的函数。它们都可以将从源地址开始的一段内存复制到目标地址,但它们的行为略有不同。memcpy() 函数将源地址中指定的字节数复制到目标地址,如果目标地址和源地址重叠,则结果不确定。memmove() 函数也将源地址中指定的字节数复制到目标地址,但它可以处理目标地址和源地址重叠的情况。在这种情况下,memmove() 函数会以一种安全而可预测的方式执行复制操作。因此,如果您需要移动一个内存块,并且知道目标地址与源地址不会重叠,那么使用 memcpy() 函数可能更高效。但如果您不能确定目标地址是否与源地址重叠,或者您确信它们重叠,那么使用 memmove() 函数更加安全。 - user142162
34
不要使用memcpy,改用std::copy。如果您的类型有一个有意义的复制构造函数,则memcpy会出错。 - Ed S.
12
你是不是真的想同时学习C和C++?它们是非常不同的编程语言。 - Ferruccio
9
我之所以这样说是因为之前没有人提到过:在C++中,几乎所有情况下都应该使用std::vector。还有一些情况下其他容器也很有用,但大多数情况下,std::vector是最佳选择。不要使用原始数组,并尽量避免使用std::array,除非必要。 - Skalli
4
选择C或C++。它们非常不同。 - MD XF
显示剩余4条评论
13个回答

191

既然你要求用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));

4
错误:'begin' 不是 'std' 的成员。 - David 天宇 Wong
28
你正在使用一个旧的编译器或者没有包含头文件。它在 <iterator>中。 - Ed S.
11
也许你应该说明你需要哪些包含。 <algorithm> 中有复制吗? - Jerry Jeremiah
24
我只是询问因为如果您不得不解释std::begin在<iterator>中,这意味着人们并没有通过谷歌搜索std::begin来找出它所在的头文件,因此他们不太可能因同样的原因搜索std::copy。如果没有人需要在评论中提问已经回答的内容,那么答案会更好。也许我应该编辑答案而不是提示您这样做。 - Jerry Jeremiah
6
你可以将“begin(src)”改为“src”,将“end(src)”改为“src+arr_size”。请注意,翻译仅涉及内容的语言转换,不包括任何解释或其他额外信息。 - Calvin
显示剩余3条评论

110
自从C++11以来,您可以使用std::array直接复制数组:
#include <array>
std::array<int, 4> A = {10, 20, 30, 40};
std::array<int, 4> B = A; // Copy array A into array B

@XAleXOwnZX:你可以像对待其他支持复制赋值的类型一样处理它。B = A - swalog
2
我认为这个函数是把A的内存地址复制到B。如果我想要将A的项目值复制到B而不改变B的内存地址,我该怎么做? - Aaron Lee
@Aaron_Lee:我刚刚测试了一下,它确实将元素复制到一个单独的内存位置中的数组中。显然,数组类有其自己的赋值运算符重载。 - Dave Rove
14
你们意识到那两行代码中没有出现赋值运算符,对吧?尽管符号看起来像是赋值运算符,但实际上调用的是复制构造函数。 - Albino Cordeiro

106

正如其他人所提到的,在C语言中,您可以使用memcpy。但请注意,这将执行原始内存复制操作,因此如果您的数据结构具有指向自身或彼此的指针,则副本中的指针仍将指向原始对象。

在C++中,如果您的数组成员是POD(即实质上是您也可以在C中不加修改地使用的类型),则同样可以使用memcpy,但通常情况下,将不允许使用memcpy。就像其他人提到的一样,要使用的函数是std::copy

话虽如此,在C++中你很少需要使用原始数组。相反,你应该使用标准容器之一(std::vector是最接近内置数组的容器,也比纯C++数组更接近Java数组 - 实际上更接近 - 但在某些情况下,std::dequestd::list可能更合适),或者如果你使用C++11,可以使用std::array,它非常接近内置数组,但像其他C++类型一样具有值语义。我在这里提到的所有类型都可以通过赋值或复制构造进行复制。此外,你可以使用迭代器语法从一个容器复制到另一个容器(甚至从内置数组中复制)。

这提供了可能性的概述(我假设所有相关的头文件都已经被包含):

#include <vector>
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的例子是错误的;源和目标被交换了。 - A T - student
1
实际上,在 memcpy 示例中,那不是唯一的错误;大小也是错误的。我现在已经修复了它,谢谢。 - celtschk
你为什么总是写std而不直接使用std的命名空间呢? - Black
你不能也使用memcpy(b, a, sizeof a)吗? - M4rk
@wcochran:是的:如果您决定重写代码以使用实际容器而不是内置数组,则无需更改该行。您需要更改的代码越少,引入的错误就越少(您需要的工作也就越少)。 - celtschk
显示剩余2条评论

20

在 C 中使用 memcpy,在 C++ 中使用 std::copy


对于一个小数组,我假设不会产生任何函数调用开销(memcpy 应该是编译器内置的)? - wcochran
@Mehrdad 我并没有说其他的话,只是发表了一下评论。而且我也没有给它点踩。 - MD XF

19

您可以使用memcpy()函数,

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

memcpy()函数将从指定的源内存地址中复制给定长度(num)的数据到目标内存地址。

如果目标内存地址和源内存地址有重叠,则应该使用memmove() 函数。

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

memmove()函数将从source指向的位置复制num个字节的值到指向内存块的destination指针所指向的位置。复制操作就像使用中间缓冲区一样进行,从而允许目标和源重叠。


3
这里必须要打个减号。原帖明确要求 C++ 解决方案,而这个回答并没有提到 memcpy 不适用的情况,即复制字节是不够的。 - Ed S.
3
@EdS。如果您还没有注意到,OP现在要求提供C C ++解决方案。 - autistic
6
当我回答时,OP正在寻求C/C++解决方案,尽管我个人认为“C/C++”对这两种语言都是一种侮辱。 :) - Deepu
好的,我没意识到它在改变。也许之前它已经说过了,而我没有注意到。减去1。 - Ed S.
@EdS。它总是说“C或C++中的一个函数”。 - Jim Balter
显示剩余2条评论

16
我喜欢Ed S.的答案,但这只适用于固定大小的数组,而不适用于将数组定义为指针的情况。
所以,对于将数组定义为指针的C++解决方案:
#include <algorithm>
...
const int bufferSize = 10;
char* origArray, newArray;
std::copy(origArray, origArray + bufferSize, newArray);

注意:不需要用1减去buffersize:
将范围[first, last)中的所有元素从第一个元素开始复制,并继续到last - 1。
参见:https://en.cppreference.com/w/cpp/algorithm/copy

1
但是我们如何确保不会发生“重叠”? - Calvinfwc
我认为你不能这样做,只需不使用原始指针即可;-) - jaques-sam

12
在C中,您可以使用memcpy。在C++中,请使用来自<algorithm>头文件的std::copy

6

我在这里提供了两种处理数组的方法,适用于C和C++语言。 在C ++中,可以使用memcpycopy,但copy不能用于C语言,如果你想在C中复制数组,必须使用memcpy

#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;是一个不好的实践,不要使用它。请使用包含更好、更更新的标准文档的cppreference.com而不是cplusplus.com。在C++中,stdio.h的等效头文件是cstdio,请使用后者。此外,该代码相当不符合C++的惯用法。如果您展示C和C++的单独解决方案,那么代码将更加清晰易懂。 - tambre

6

只需在您的代码中包含标准库即可。

#include<algorithm>

数组大小将用n表示。

您的旧数组:

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

声明一个新的数组,将旧数组的值复制到其中

int newArray[n];

请使用这个。
copy_n(oldArray,n,newArray);

3

在C++11中,您可以使用适用于std容器的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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接