Обучение C#

Формула программиста
основатель — Волосатов Евгений Витольдович

Одномерные массивы

Данные одинакового типа удобно хранить и обрабатывать с использованием массива.
Массив — это непрерывный участок памяти, в котором содержатся элементы одного типа. Массив имеет идентификатор (имя массива), который используется для обращения к отдельным его элементам.
Каждый элемент массива хранится в отдельной ячейке (или ячейках) памяти и имеет свой индекс (порядковый номер в составе массива) и значение.
Все массивы можно условно разделить на
  • одномерные массивы;
  • многомерные массивы;
  • массивы массивов.
В данной статье речь пойдет об одномерных массивах.

Для использования массива его необходимо объявить и выделить память для хранения его элементов. Для объявления одномерного массива используется следующий синтаксис:

тип имя;

В этой строке тип указывает на тип элементов, которые будут храниться в массиве. Имя предполагает ячейку, в которой будет храниться ссылка (адрес) участка памяти, в котором и будут размещаться элементы массива. Но на текущий момент сам участок памяти для хранения элементов массива еще не выделен.
Для его выделения используется операция new без инициализации или с инициализацией:

имя new тип[количество];
имя new тип[] {выражение1, выражение2, выражениеn};

Результатом выполнения операции new является ссылка на выделенный участок памяти для хранения массива.
При выделении памяти всем элементам массива присваивается значение по умолчанию (для базовых типов данных это значение равно 0).
Объявление массива и выделение памяти для хранения его элементов можно осуществить в одной строке. Например,

int [] mas = new int[5];

После того как объявлен массив и выделена память для хранения его элементов, можно обратиться к элементам массива с использованием соответствующего индекса:

имя[индекс]

Начальный элемент массива всегда имеет индекс 0, последний элемент имеет индекс КоличествоЭлементов-1. То есть если массив содержит 5 элементов, то эти элементы имеют индексы 0, 1, 2, 3, 4.

Создание массива

В качестве примера рассмотрим задачу найти максимальный элемент массива, состоящего из n элементов.
Сначала введем количество элементов, которые будут храниться в массиве, затем последовательно в цикле введем сами элементы. Для поиска максимального элемента можно воспользоваться параметрическим циклом.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
namespace MyProgram
{
  class Program
  {
    static void Main(string[] args)
    {
      int n = int.Parse(Console.ReadLine());
      int [] arr = new int [n];
      for (int i = 0; i < n; i++)
        arr[i] = int.Parse(Console.ReadLine());
      int max = arr[0];
      for (int i = 0; i < n; i++)
        if (arr[i] > max) max = arr[i];
      Console.WriteLine(max);
      Console.ReadKey();
    }
  }
}

Результат выполнения программы представлен на рисунке.
image articles/506/506_1.png
Поиск максимума можно осуществить с использованием цикла перебора элементов foreach.

13
14
      foreach (int a in arr)
        if (a > max) max = a;

Все массивы в C# являются наследниками класса System.Array, который, в свою очередь, наследует класс System.Object. Поэтому все массивы обладают рядом свойств и методов, присущих классу Array.
Среди свойств класса Array наиболее популярным является свойство Length, возвращающее количество элементов в массиве.
Кроме того, класс Array содержит ряд методов для работы с массивами, некоторые из которых будут рассмотрены ниже.

Запись и считывание элементов массива

Для обращения к элементам массива можно воспользоваться обращением к элементу по его индексу, как это было показано в предыдущем примере. Но класс Array также поддерживает методы для считывания и установки значений элементов массива:
  • SetValue(значение, индекс) — для записи значения в элемент массива;
  • GetValue(индекс) — для считывания значения из элемента массива. Функция возвращает объект типа Object, для дальнейшего использования которого необходимо явное приведение его к типу элементов массива.
Пример использования этих методов, а также свойства Length, для нахождения максимума в массиве
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
namespace MyProgram
{
  class Program
  {
    static void Main(string[] args)
    {
      int n = int.Parse(Console.ReadLine());
      int [] mas = new int [n];
      for (int i = 0; i < mas.Length; i++)
        mas.SetValue(int.Parse(Console.ReadLine()), i);
      int max = (int)mas.GetValue(0);
      for (int i = 0; i < mas.Length; i++)
      {
        int a = (int)mas.GetValue(i);
        if (a > max) max = a;
      }
      Console.WriteLine(max);
      Console.ReadKey();
    }
  }
}

Для установки диапазона элементов массива в значение по умолчанию можно использовать статический метод класса ArrayClear(), в качестве аргументов которому передаются ссылка на массив, начальный элемент, с которого необходимо осуществить сброс элементов к начальным значениям и длина диапазона (количество таких элементов.
Пример использования метода Clear() для обнуления диапазона элементов.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
namespace MyProgram
{
  class Program
  {
    static void Main(string[] args)
    {
      int n = int.Parse(Console.ReadLine());
      int [] arr = new int [n];
      for (int i = 0; i < arr.Length; i++)
        arr[i] = int.Parse( Console.ReadLine());
      for (int i = 0; i < arr.Length; i++)
        Console.Write(arr[i] + " ");
      Array.Clear(arr,1,2);
      Console.WriteLine();
      for (int i = 0; i < arr.Length; i++)
        Console.Write(arr[i] + " ");
      Console.ReadKey();
    }
  }
}

Результат работы программы:
image articles/506/506_3.png

Копирование массива

Для копирования массивов можно использовать один из двух методов класса ArrayClone() и CopyTo(). Оба метода создают поверхностную копию массива, то есть копируют элементы из одного массива в другой массив. При этом если элементы массива являются ссылками, то копируются сами значения этих ссылок, а сам объект, на который они ссылаются, остается единственным.
Кардинальное отличие методов Clone() и CopyTo() заключается в том, что метод Clone() самостоятельно выделяет память под вновь создаваемый массив и заполняет ее копиями элементов, а метод CopyTo() предусматривает, что память должна быть предварительно выделена под заполняемый этим методом массив в достаточном объеме.

Метод Clone() возвращает объект класса Object, который необходимо явно привести к ссылке на массив указанного типа.
Рассмотрим пример копирования массива с помощью функции Clone():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
namespace MyProgram
{
  class Program
  {
    static void Main(string[] args)
    {
      int n = int.Parse(Console.ReadLine());
      int [] arra = new int [n];
      for (int i = 0; i < arra.Length; i++)
        arra[i] = int.Parse(Console.ReadLine());
      int[] arrb = (int[])arra.Clone();
      for (int i = 0; i < arrb.Length; i++)
        Console.Write(arrb[i] + " ");
      Console.ReadKey();
    }
  }
}

Пример использования метода CopyTo() для копирования массива. В качестве аргументов методу CopyTo() передаются ссылка на массив, куда будут копироваться элементы и индекс начального элемента для копирования.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
namespace MyProgram
{
  class Program
  {
    static void Main(string[] args)
    {
      int n = int.Parse(Console.ReadLine());
      int [] arra = new int [n];
      for (int i = 0; i < arra.Length; i++)
        arra[i] = int.Parse(Console.ReadLine());
      int[] arrb = new int[n];
      arra.CopyTo(arrb, 0);
      for (int i = 0; i < arrb.Length; i++)
        Console.Write(arrb[i] + " ");
      Console.ReadKey();
    }
  }
}

Кроме того, для копирования массива можно использовать статические методы класса Array:
  • Copy(), в качестве аргументов которого передаются ссылка на копируемый массив, ссылка на массив-приемник (память для хранения элементов этого массива предварительно должна быть выделена в достаточном количестве) и количество копируемых элементов. Возможна также перегрузка данного метода с указанием начального индекса массива-источника и массива-приемника.
  • ConstrainedCopy() — метод, имеющий единственный вариант вызова, и в качестве аргументов ему передаются
    • ссылка на копируемый массив,
    • индекс элемента, с которого начинается копирование
    • ссылка на массив-приемник
    • индекс элемента, на место которого начинается копирование
    • количество копируемых элементов.
    Метод гарантирует, что при невозможности скопировать весь диапазон значений все изменения будут отменены.

Рассмотрим пример, копирования массива с использованием метода Copy():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
namespace MyProgram
{
  class Program
  {
    static void Main(string[] args)
    {
      int n = int.Parse(Console.ReadLine());
      int [] arra = new int [n];
      for (int i = 0; i < arra.Length; i++)
        arra[i] = int.Parse( Console.ReadLine());
      int[] arrb = new int[n];
      Array.Copy(arra, arrb, arra.Length);
      for (int i = 0; i < arrb.Length; i++)
        Console.Write(arrb[i] + " ");
      Console.ReadKey();
    }
  }
}

Использование метода ConstrainedCopy() для копирования массива:
13
      Array.ConstrainedCopy(arra, 0, arrb, 0, arra.Length);

Изменение размеров массива

При выделении памяти под элементы массива, выделенный участок памяти может хранить фиксированное число элементов. Если размер массива необходимо увеличить или уменьшить, то необходимо сначала создать новый массив, потом скопировать в него значения требуемых элементов текущего массива, после чего освободить память, выделенную под старый массив.
С этой целью может использоваться статический метод Resize() класса Array, который в качестве аргументов принимает ссылку на массив и новое количество его элементов. Если количество элементов необходимо уменьшить, то последние элементы массива не будут сохранены. Если количество элементов необходимо увеличить, то вновь созданные элементы заполнятся значениями по умолчанию.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
namespace MyProgram
{
  class Program
  {
    static void Main(string[] args)
    {
      int n = int.Parse(Console.ReadLine());
      int [] arr = new int [n];
      for (int i = 0; i < arr.Length; i++)
        arr[i] = int.Parse(Console.ReadLine());
      Array.Resize(ref arr, 4);
      for (int i = 0; i < arr.Length; i++)
        Console.Write(arr[i] + " ");
      Console.ReadKey();
    }
  }
}

Сортировка, поиск и переворот массива

Для сортировки массива используется статический метод Sort() класса Array, в качестве аргумента которому передается ссылка на сортируемый массив. Выбор метода сортировки осуществляется в зависимости от длины сортируемого массива.
Для поиска значения элемента в отсортированном массиве может использоваться статический метод BinarySearch() класса Array, которому в качестве аргументов передаются ссылка на массив и искомое значение. Метод возвращает индекс элемента в массиве с заданным значением. Если элемент в массиве не найден, возвращается отрицательное значение. Если массив содержит несколько искомых элементов, возвращается индекс одного из них.
Для поиска элемента в неотсортированном массиве по значению также можно воспользоваться статическими методами IndexOf() и LastIndexOf() класса Array, в качестве аргументов которым передаются ссылка на массив и искомое значение. Возвращаемое значение функций — индекс первого и последнего элементов соответственно в массиве, равных искомому. Если элемент с искомым значением в массиве не найден, возвращается отрицательное значение индекса.
Класс Array содержит метод Reverse(), предназначенный для изменения порядка следования всех элементов массива на противоположный.
Ниже приведен пример использования перечисленных методов.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
namespace MyProgram
{
  class Program
  {
    static void Main(string[] args)
    {
      int n = int.Parse(Console.ReadLine());
      int [] arr = new int [n];
      for (int i = 0; i < arr.Length; i++)
        arr[i] = int.Parse(Console.ReadLine());
      for (int i = 0; i < arr.Length; i++)
        Console.Write(arr[i] + " ");
      Console.WriteLine();
      Console.WriteLine("First(5)=" + Array.IndexOf(arr, 5));
      Console.WriteLine("Last(5) =" + Array.LastIndexOf(arr, 5));
      Array.Sort(arr);
      for (int i = 0; i < arr.Length; i++)
        Console.Write(arr[i] + " ");
      Console.WriteLine();
      Console.WriteLine("Find(5) =" + Array.BinarySearch(arr, 5));
      Array.Reverse(arr);
      for (int i = 0; i < arr.Length; i++)
        Console.Write(arr[i] + " ");
      Console.WriteLine();
      Console.ReadKey();
    }
  }
}

Результат выполнения программы представлен на рисунке.
image articles/506/506_2.png


Автор: Вставская Елена Владимировна

 
Написать комментарий:




Начинаем практику по языку C#




Чтобы стать хорошим программистом — нужно писать программы. На нашем сайте очень много практических упражнений.

После заполнения формы ты будешь подписан на рассылку «C# Вебинары и Видеоуроки», у тебя появится доступ к видеоурокам и консольным задачам.

Несколько раз в неделю тебе будут приходить письма — приглашения на вебинары, информация об акциях и скидках, полезная информация по C#.

Ты в любой момент сможешь отписаться от рассылки.