Existe-t-il une fonction pour copier un tableau en C / C ++?

91

Je suis un programmeur Java apprenant le C / C ++. Je sais donc que Java a une fonction comme System.arraycopy (); pour copier un tableau. Je me demandais s'il y avait une fonction en C ou C ++ pour copier un tableau. Je n'ai pu trouver une implémentation que pour copier un tableau en utilisant une boucle for, des pointeurs, etc. Existe-t-il une fonction que je peux utiliser pour copier un tableau?

JL
la source
7
man memmoveetman memcpy
Tim Cooper
28
N'utilisez pas memcpy, utilisez std::copy. Si votre type a un constructeur de copie significatif, il memcpyfera la mauvaise chose.
Ed S.
10
Essayez-vous réellement d'apprendre le C et le C ++ en même temps? Ce sont des langues très différentes.
Ferruccio
1
Eh bien, j'ai appris un peu de C et maintenant j'ai récemment commencé à apprendre le C ++. D'après ce que j'ai lu sur une ressource en ligne, je pensais que C ++ n'était qu'un langage avec de nombreuses fonctionnalités supplémentaires au langage C.
JL
6
Je dis cela parce que personne ne l'a mentionné auparavant: en C ++, vous devriez utiliser std :: vector dans presque tous les cas. Il y a des cas où d'autres conteneurs sont également utiles, mais dans la plupart des cas, std :: vector sera la meilleure option. N'utilisez pas de tableaux bruts en C ++ et essayez d'éviter std :: array à moins que cela ne soit nécessaire.
Skalli

Réponses:

79

Depuis C ++ 11, vous pouvez copier des tableaux directement avec std::array:

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

Voici la documentation sur std :: array

taocp
la source
@XAleXOwnZX: la même chose que tout autre type prenant en charge l'affectation de copie. B = A.
swalog
2
Je pense que la fonction est de copier l'adresse mémoire de A vers B. Si j'essaie de copier les valeurs des éléments de A vers B sans changer l'adresse mémoire de B. Comment puis je faire ça?
Aaron Lee
@Aaron_Lee: Je viens de le tester, et il copie véritablement les éléments dans un tableau dans un emplacement mémoire séparé. La classe de tableau a évidemment sa propre surcharge pour l'opérateur d'affectation.
Dave Rove
4
Vous vous rendez compte qu'aucun opérateur d'affectation n'apparaît dans ces deux lignes de code, n'est-ce pas? C'est le constructeur de copie qui est appelé même si la notation ressemble à l'opérateur d'affectation.
Albino Cordeiro
138

Puisque vous avez demandé une solution 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));
Ed S.
la source
2
erreur: 'begin' n'est pas membre de 'std'
David 天宇 Wong
23
@David 天宇 Wong: Vous utilisez un ancien compilateur ou vous n'avez pas inclus l'en-tête. C'est dans<iterator>
Ed S.
9
Peut-être devriez-vous dire ce dont vous avez besoin. La copie est-elle incluse <algorithm>?
Jerry Jeremiah
15
Je demande seulement parce que si vous deviez expliquer que std :: begin était dans <iterator>, cela signifie que les gens ne recherchent pas sur Google std :: begin pour savoir dans quel en-tête il se trouve, il est donc peu probable qu'ils utilisent Google std :: copy pour le même raison. Cela fait une meilleure réponse si personne n'a à demander des choses qui ne sont répondues que dans les commentaires. J'aurais peut-être dû simplement modifier la réponse au lieu de vous demander de le faire.
Jerry Jeremiah
3
vous pouvez changer begin (src) en src et end (src) en src + arr_size
Calvin
82

Comme d'autres l'ont mentionné, en C, vous utiliseriez memcpy. Notez cependant que cela fait une copie de mémoire brute, donc si vos structures de données ont un pointeur vers elles-mêmes ou les unes vers les autres, les pointeurs de la copie pointeront toujours vers les objets d'origine.

En C ++, vous pouvez également utiliser memcpysi les membres de votre tableau sont des POD (c'est-à-dire essentiellement des types que vous auriez pu également utiliser inchangés en C), mais en général, nememcpy seront pas autorisés. Comme d'autres l'ont mentionné, la fonction à utiliser est std::copy.

Cela dit, en C ++, vous devez rarement utiliser des tableaux bruts. Au lieu de cela, vous devez soit utiliser l'un des conteneurs standard ( std::vectorest le plus proche d'un tableau intégré, et je pense aussi que le plus proche des tableaux Java - plus proche que les tableaux C ++ simples, en effet -, mais std::dequeou std::listpeut être plus approprié dans certains cas) ou, si vous utilisez C ++ 11, std::arrayqui est très proche des tableaux intégrés, mais avec une sémantique de valeur comme les autres types C ++. Tous les types que j'ai mentionnés ici peuvent être copiés par cession ou par construction de copie. De plus, vous pouvez "faire une copie croisée" d'un opne à un autre (et même d'un tableau intégré) en utilisant la syntaxe d'itérateur.

Cela donne un aperçu des possibilités (je suppose que tous les en-têtes pertinents ont été inclus):

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;
}
celtschk
la source
1
L'exemple memcpy est faux; la source et la destination sont commutées.
AT - étudiant
1
En fait, ce n'était pas la seule erreur de l' memcpyexemple; la taille était également fausse. Je l'ai maintenant réparé, merci.
celtschk
pourquoi écrivez-vous std tout le temps au lieu d'utiliser simplement l'espace de noms de std ???
Black
ne pouvez-vous pas faire memcpy (b, a, sizeof a); aussi?
rodi
Un tableau Java ressemble plus à un tableau std:arrayà un autre std::vector, car il a une taille fixe.
Bart van Heukelom
17

Vous pouvez utiliser le memcpy(),

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

memcpy()copie les valeurs d' numoctets de l'emplacement pointé par sourcedirectement vers le bloc de mémoire pointé par destination.

Si les destinationet se sourcechevauchent, vous pouvez utiliser memmove().

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

memmove()copie les valeurs d' numoctets de l'emplacement pointé par sourcevers le bloc de mémoire pointé par destination. La copie a lieu comme si un tampon intermédiaire était utilisé, permettant à la destination et à la source de se chevaucher.

Deepu
la source
3
Je vais devoir -1 ici. L'OP demande spécifiquement une solution C ++ et cette réponse ne dit rien des situations dans lesquelles memcpyc'est faux, c'est-à-dire que la copie d'octets est insuffisante.
Ed S.
2
@EdS. Au cas où vous ne l'auriez pas remarqué, l'OP demande maintenant une solution C ou C ++.
autiste
4
Quand j'ai répondu, l'OP demandait des solutions C / C ++, bien que je pense personnellement que "C / C ++" est une insulte aux deux langages. :)
Deepu
assez juste, je ne savais pas que cela changeait. Peut-être qu'il l'a même dit plus tôt et je l'ai manqué. -1 supprimé.
Ed S.
2
@EdS Je pensais que c'était 2 minutes, mais peu importe, au moment où cette réponse a été publiée, la question faisait référence à la fois au C et au C ++. Même si je me trompais et que la question à un moment donné ne disait que C ++, le vote défavorable n'était pas justifié.
Jim Balter
16

Utilisation memcpyen C, std::copyen C ++.

user541686
la source
Pour un petit tableau, je suppose que ni l'un ni l'autre n'encourent de surcharge d'appel de fonction ( memcpydevrait être un compilateur intrinsèque)?
wcochran
@Mehrdad Je n'ai pas dit le contraire; juste faire un commentaire. Et je ne l'ai pas contre-voté non plus.
MD XF
12

J'aime la réponse d'Ed S., mais cela ne fonctionne que pour les tableaux de taille fixe et non lorsque les tableaux sont définis comme des pointeurs.

Donc, la solution C ++ où les tableaux sont définis comme des pointeurs:

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

Remarque : pas besoin de déduire buffersizeavec 1:

  1. Copie tous les éléments de la plage [premier, dernier) en commençant par le premier et en continuant au dernier - 1

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

DrumM
la source
10

En C, vous pouvez utiliser memcpy. En C ++, utilisez à std::copypartir de l'en- <algorithm>tête.

Pete Becker
la source
3

en C ++ 11, vous pouvez utiliser Copy()cela fonctionne pour les conteneurs 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;
}
MORTEL
la source
Ce serait une meilleure idée de sortir la std::endboucle, pour des raisons de performances (c1 ne change pas ou n'invalide pas les itérateurs pendant la boucle, il est donc inutile de recalculer la fin).
celtschk
3

Je donne ici 2 façons de faire face au tableau, pour le langage C et C ++. memcpy et copier les deux sont utilisables sur C ++ mais la copie n'est pas utilisable pour C, vous devez utiliser memcpy si vous essayez de copier un tableau en 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;
}
FaridLU
la source
4
using namespace std;est une mauvaise pratique . Ne l'utilisez jamais. Au lieu de cplusplus.com, veuillez utiliser cppreference.com, qui comprend une documentation bien meilleure et à jour de la norme. L' stdio.héquivalent en C ++ est cstdio, utilisez cela à la place. De plus, le code est plutôt C ++ non idiomatique. Je pense que ce serait beaucoup plus clair si vous aviez présenté des solutions séparées pour C et C ++.
tambre
3

Incluez simplement la bibliothèque standard dans votre code.

#include<algorithm>

La taille du tableau sera indiquée par n

Votre ancien tableau

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

Déclarez un nouveau tableau dans lequel vous devez copier votre ancienne valeur de tableau

int newArray[n];

Utilisez ceci

copy_n(oldArray,n,newArray);
Ankit Singh
la source
1

Premièrement, comme vous passez au C ++, il est recommandé d'utiliser le vecteur à la place du tableau traditionnel . En outre, copier un tableau ou un vecteur std::copyest le meilleur choix pour vous.

Visitez cette page pour savoir comment utiliser la fonction de copie: http://en.cppreference.com/w/cpp/algorithm/copy

Exemple:

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());
Nhan Nguyen Tri Thanh
la source