Referenční typy - pole
9. Kopírování pole
Pole jsou referenční typy, tzn., že pokud je vytvořena instance typu pole (tj. instance třídy System.Array), proměnná se odkazuje na místo v paměti (haldě), kde jsou uloženy jednotlivé prvky tohoto pole. Pokud tedy přiřazujeme proměnné proměnnou, nevytváříme kopii proměnné, ale přiřazujeme odkaz na tentýž blok paměti, na který odkazuje kopírovaná proměnná, jak popisuje následující příklad – viz Kód 1 (využijme předchozí příklad deklarace jednorozměrného pole včetně inicializace jeho prvků s odvozením velikosti pole pomocí kompilátoru).
static void Main(string[] args) { //Vytvoření instance pole o 5 prvcích včetně inicializace int[] poctyLidi = { 7, 5, 2, 4, 9 }; /*Nevytvoří se kopie pole, ale vytváříme referenci na stejný blok paměti, * kterou využívá pole(instance) poctyLidi*/ int[] PoctyLidi2 = poctyLidi; //Čekání na stisk klávesy -> ukončení programu Console.ReadKey(); }
Kód 1: Příklad kopie reference, kterou používá první instance jednorozměrného pole
Podstata předchozího kódu (viz Kód 1) je zachycena v následujícím obrázku – viz Obrázek 1. Pokud tedy měníme některý prvek v poli poctyLidi2, mění se zároveň prvek v poli poctyLidi.

Obrázek 1: Přiřazení reference na stejný blok paměti na haldě
Jak tedy vytvořit kopii pole, tj. vytvoření instance s kopií obsahů jednotlivých prvků, které jsou uloženy na haldě?
Ilustrativní příklad PoleLidiKopie
Program PoleLidiKopie
- Popis: Kopie obsahů všech celočíselných prvků jednorozměrného pole pomocí cyklu s krokem
- Zadání: Vytvořte instanci jednorozměrného celočíselného pole o 5 prvcích: 7, 5, 2, 4, 9. Instance se bude jmenovat poctyLidi. V metodě Main zkopírujte obsah všech celočíselných prvků pole poctyLidi a nazvěte jej kopie
- Řešení: Bude postupně probráno v následujícím textu
Postup v kódu je následující: musíme vytvořit nové pole (tj. novou instanci) stejného datového typu, jako je kopírované pole. Toto pole (instance) musí mít stejnou délku jako kopírované pole – viz Kód 2. Dále musíme kopírovat obsah všech prvků kopírovaného pole do prvků nově vytvářeného pole. Pro určení velikosti pole, tak i pro určení počtu iterací v cyklu, použijeme vlastnosti Length, která poskytne velikost kopírovaného pole.
static void Main(string[] args) { //Vytvoření instance pole o 5 prvcích včetně inicializace int[] poctyLidi = { 7, 5, 2, 4, 9 }; /*Vytvoření nového pole (instance) se stejnou délkou jakou má * kopírované pole (instance)*/ int[] kopie = new int[poctyLidi.Length]; //Procházení všech prvků pole for (int i = 0; i < poctyLidi.Length; i++) { //Přiřazení obsahu prvku kopírovaného pole do nově vytvořeného pole kopie[i] = poctyLidi[i]; } }
Kód 2: Kopie jednorozměrného pole
Podstata předchozího kódu (viz Kód 2) je zachycena v následujícím obrázku – viz Obrázek 2. Pokud tedy měníme některý prvek v poli kopie, již se nebude měnit prvek v poli poctyLidi.

Obrázek 2: Vytvoření kopie pole
Ilustrativní příklad PoleLidiCopyTo
Program PoleLidiCopyTo
- Popis: Kopie obsahů všech celočíselných prvků jednorozměrného pole pomocí metody CopyTo
- Zadání: Vytvořte instanci jednorozměrného celočíselného pole o 5 prvcích: 7, 5, 2, 4, 9. Instance se bude jmenovat poctyLidi. V metodě Main zkopírujte obsah všech celočíselných prvků pole poctyLidí pomocí metody CopyTo a nazvěte jej kopie
- Řešení: Bude postupně probráno v následujícím textu
Kopírování pole je dosti běžnou činností, proto třída System.Array nabízí některé užitečné metody pro práci s polem např. CopyTo – viz Kód 3. Tato metoda zkopíruje obsah pole do jiného pole vzhledem k zadanému počátečnímu indexu, odkud se mají prvky pole kopírovat.
static void Main(string[] args) { //Vytvoření instance pole o 5 prvcích včetně inicializace int[] poctyLidi = { 7, 5, 2, 4, 9 }; //Vytvoření nového pole se stejnou délkou jako kopírované pole int[] kopie = new int[poctyLidi.Length]; //Kopírování všech prvků od indexu 0 poctyLidi.CopyTo(kopie, 0); }
Kód 3: Kopie jednorozměrného pole poctyLidi pomocí metody CopyTo
Ilustrativní příklad PoleLidiCopy
Program PoleLidiCopy
- Popis: Kopie obsahů všech celočíselných prvků jednorozměrného pole pomocí metody Copy
- Zadání: Vytvořte instanci jednorozměrného celočíselného pole o 5 prvcích: 7, 5, 2, 4, 9. Instance se bude jmenovat poctyLidi. V metodě Main zkopírujte obsah všech celočíselných prvků pole poctyLidí pomocí metody Array.Copy a nazvěte jej kopie
- Řešení: Bude postupně probráno v následujícím textu
Dalším způsobem kopírování pole je použít statickou metodu Copy třídy System.Array. Stejně jako u metody CopyTo musíme před voláním metody Copy vytvořit instanci pole, kam budeme kopírovat obsah kopírovaného pole – viz Kód 4. Pokud nezadáme platnou hodnotu délky pole např. zápornou hodnotu, metoda vyvolá výjimka typu ArgumentOutOfRangeException. V opačném případě specifikovaní větší délky, než je skutečná délka zdrojového pole, metoda vyvolá výjimku ArgumentException.
static void Main(string[] args) { //Vytvoření instance pole o 5 prvcích včetně inicializace int[] poctyLidi = { 7, 5, 2, 4, 9 }; //Vytvoření nového pole se stejnou délkou jako kopírované pole int[] kopie = new int[poctyLidi.Length]; //Kopírování všech prvků - v závorce: zdrojové pole, cílové pole, délka pole Array.Copy(poctyLidi, kopie, kopie.Length); }
Kód 4: Kopie jednorozměrného pole poctyLidi pomocí metody Array.Copy
Ilustrativní příklad PoleLidiClone
Program PoleLidiClone
- Popis: Kopie obsahů všech celočíselných prvků jednorozměrného pole pomocí metody Clone
- Zadání: Vytvořte instanci jednorozměrného celočíselného pole o 5 prvcích: 7, 5, 2, 4, 9. Instance se bude jmenovat poctyLidi. V metodě Main klonujte obsah všech celočíselných prvků pole poctyLidí pomocí metody Clone a nazvěte jej kopie
- Řešení: Bude postupně probráno v následujícím textu
Další alternativou kopírování pole je metoda Clone třídy System.Array. Tato metoda vytvoří a zároveň zkopíruje obsah pole – viz Kód 5. Tato metoda vrací jako výsledek datový typ object. Proto objekt musí být přetypován na datový typ prvků pole, abychom jej mohli přiřadit kopii pole.
static void Main(string[] args) { //Vytvoření instance pole o 5 prvcích včetně inicializace int[] poctyLidi = { 7, 5, 2, 4, 9 }; //Vytvoření klonovaného pole jako typ object -> přetypování int[] kopie = (int[])poctyLidi.Clone(); }
Kód 5: Klonování jednorozměrného pole poctyLidi pomocí metody Clone
Metody Clone, CopyTo a Copy vytvářejí mělkou kopii (anglicky „Shalow Copy ") pole. Pokud prvky ve zkopírovaném poli obsahují odkazy, metoda Clone zkopíruje odkazy namísto samotných objektů. Po zkopírování se obě pole odkazují na stejné objekty. Pokud potřebujeme vytvořit hlubokou kopii (anglicky "Deep Copy") takového pole, musíme použít příslušný kód ve smyčce for - Obrázek 2. [6]