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.

Přiřazení reference na stejný blok paměti na haldě

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.

Kopie pole

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]