Task:C# Beginner2 Victory is close Introduction to arrays in "Copy the arrays"

У слеці виникло питання:

using System;

namespace Arrays
{
    class ArraysCopy
    {
        public static void Main(string[] args)
        {
            double[] myArray = GetNumbersFromConsole();

            for (int i = 0; i < myArray.Length; ++i)
                Console.WriteLine(myArray[i]);
        }
        
        static double[] GetNumbersFromConsole()
        {
            int count = int.Parse(Console.ReadLine());
            double[] result = new double[count];

            for(int i = 0; i < count; ++i)
            {
                result[i] = double.Parse(Console.ReadLine());                
            }

            return result;
        }
    }
}

Хочу звернути увагу на те що масив копіюється два рази у вкладенці “порівняння”.
Зверху мій код. Знизу код Кодізі.

Ось строка котру я пропустила double[] copy = new double[myArray.Length];
using System;

namespace Arrays
{
    class ArraysCopy
    {
        public static void Main(string[] args)
        {
            double[] myArray = GetNumbersFromConsole();
            double[] copy = new double[myArray.Length];

            for (int i = 0; i < myArray.Length; ++i)
                copy[i] = myArray[i];

            for (int i = 0; i < myArray.Length; ++i)
                Console.WriteLine(copy[i]);
        }
        
        static double[] GetNumbersFromConsole()
        {
            int count = int.Parse(Console.ReadLine());
            double[] result = new double[count];

            for(int i = 0; i < count; ++i)
            {
                result[i] = double.Parse(Console.ReadLine());
            }

            return result;
        }
    }
}
double[] myArray = GetNumbersFromConsole();

ця строчка кода не “Копіює” масив (array), а створює його і він існує в одному екземплярі.

Масиви це “reference type” (посилання), а не “value type” (значення). Саме тому, посилання яке було створенно в середині метода GetNumbersFromConsole було передано в змінну “myArray”.

Нам же треба зробити копію масиву. В більшості випадків, коли програмісти кажуть “копіювати”, вони мають на увазі “копіювати значення”. Рішення кодізі саме це і робить. Ми створюємо новий масив такої самої довжини і копіюємо значення кожного елементу.

Спробуйте порівняти 2 варіанти методу Main. В першому варіанті ми створюємо новий масив копіювавши кожний елемент.

public static void Main(string[] args)
{
    double[] myArray = GetNumbersFromConsole();
    double[] copy = new double[myArray.Length];

    for (int i = 0; i < myArray.Length; ++i)
        copy[i] = myArray[i];
    
    // змініюємо значення першого елементу оригінального масиву
    myArray[0] = 42;
    Console.WriteLine("Let's output original array after we changed first element of original array:");
    for (int i = 0; i < myArray.Length; ++i)
        Console.WriteLine(myArray[i]);

    Console.WriteLine("Let's output copy array after we changed first element of original array:");
    for (int i = 0; i < myArray.Length; ++i)
        Console.WriteLine(copy[i]);
}

В другому варіанті, ми кажемо що наш новий масив посилається на старий масив шляхом double[] copy = myArray;

public static void Main(string[] args)
{
    double[] myArray = GetNumbersFromConsole();
    double[] copy = myArray;
    
    // змініюємо значення першого елементу оригінального масиву
    myArray[0] = 42;
    Console.WriteLine("Let's output original array after we changed first element of original array:");
    for (int i = 0; i < myArray.Length; ++i)
        Console.WriteLine(myArray[i]);

    Console.WriteLine("Let's output copy array after we changed first element of original array:");
    for (int i = 0; i < myArray.Length; ++i)
        Console.WriteLine(copy[i]);
}
3 Likes

Метод ніби зникає після завершення і більше не існує значень котрі він повернув, доки його не викличуть знову? Тому myArray = це не копія, а єдиний існуючий масив після того як закінчився метод?

1 Like

Побачила різницю між прикладами.

Трішки не так, але близько. Існує таке поняття як “scope” - область дії.
В мові с# межі scope - це код між “{” та “}”.

Всі змінні value type (значення, як от int), які створенні в середині метода - існують лише в середині метода.
Всі змінні reference type (посилання, як от масиви), які створенні в середині метода, АЛЕ не використовуються назовні - існують лише в середині метода, ОДНАК якщо вони використовуються ззовні - таке посилання буде видно і в інших частинах коду.

В нашому випадку, в середині метода ми створюємо новий масив double[] result = new double[count];. Оскільки ми його і вертаємо наззовні (return result;) - то змінна double[] myArray = GetNumbersFromConsole(); отримає посилання на саме цей масив. (як ви вірно і сказали)

якщо ж ми викличемо цей метод знову - ми створимо НОВИЙ масив

3 Likes

Для аналогії:
Уявіть що масив це “стікер” (такий жовтий папірець для нотаток).
Кожного разу як ви викликаєте new double[number] - ви відриваєте такий стікер і number вказує скільки там є рядків для запису.

Ви можете записати в нього дані (result[0] = 23; result[1] = 42;). Так само ви можете взяти цей стікер і віднести в іншу кімнату (return result;). Такий стікер з такими даними існує в одному екземплярі.

Якщо вам треба скопіювати стікер, ви не можете його просто “забрати”, вам потрібно взяти новий стікер (double[] copy = new double[myArray.Length];) та записати в ньому такі самі дані як в оригінальному стікері

3 Likes

Здається зрозуміла, дякую)