# Глава 4. Массивы
## Понятие массива и его представление в памяти
Массив — это структура данных, которая хранит упорядоченный набор однотипных элементов. Вот как можно объявить и инициализировать массив, в котором находятся пять целых чисел:
```go {.example_for_playground .example_for_playground_001}
arr := [5]int{1, 2, 3, 4, 5}
```
Длина массива — это часть типа массива. Так, `arr` из примера выше имеет тип `[5]int`.
`[5]int` в памяти компьютера — это всего лишь пять целочисленных значений, расположенных последовательно. Массивы в Go — это последовательность значений. Переменная массива означает весь массив, а не указатель на первый элемент, как, например, в языке C. Это означает, что когда вы передаете массив в функцию, то передается копия всего массива, а не указатель на него. Такого поведения можно избежать, создав указатель на массив и передав его в качестве аргумента.
Чтобы не указывать количество элементов массива `[5]int`, используется следующая запись:
```go {.example_for_playground .example_for_playground_002}
arr := [...]int{1, 2, 3, 4, 5}
```
В этом случае компилятор сам посчитает количество элементов. Тип массива `arr` от этого не поменяется, и будет по-прежнему `[5]int`.
Можно инициализировать лишь первые несколько элементов, тогда оставшиеся получат значение по умолчанию:
```go {.example_for_playground .example_for_playground_003}
arr := [10]int{1, 2, 3, 4, 5}
```
Массив в этом случае содержит следующие элементы:
```
[1 2 3 4 5 0 0 0 0 0]
```
Если нет необходимости инициализировать массив конкретными значениями, то он объявляется следующим образом:
```go
var arr [5]int
```
Тогда каждому элементу массива будет присвоено значение по умолчанию для этого типа.
Узнать длину массива можно с помощью функции `len()`:
```go
fmt.Println(len(arr))
```
Индексация элементов массива начинается с нуля, т.е. в примере ниже элемент с индексом `0` массива `arr` равен `1`. Элемент с индексом `4` равен `5`. Длина массива `arr` равна `5`.
```go
arr := [5]int{1, 2, 3, 4, 5}
```
Чтобы обратиться к элементу массива с индексом `i`, достаточно поставить после имени массива квадратные скобки с этим индексом `[i]`:
```go
arr[3] = 250
```
Можно инициализировать конкретные элементы массива по их индексу:
```go
arr := [10]int{4: 100, 7: 400}
```
Массив в этом случае содержит следующие элементы:
```
[0 0 0 0 100 0 0 400 0 0]
```
Простое число — это натуральное число, которое больше `1` и делится только на себя и на `1`. {.task_text}
Напишите программу, которая заполнит массив из `100` элементов первыми `100` простыми числами. Выведите полученный массив на экран. {.task_text}
```go {.task_source #golang_chapter_0040_task_0010}
package main
import "fmt"
func main() {
// ваш код здесь
}
```
Проверяйте на простоту все числа подряд и добавляйте простые в массив до тех пор, пока не заполните его. {.task_hint}
``` golang {.task_answer}
package main
import "fmt"
func main() {
var arr [100]int
i := 0 // индекс простого числа
number := 2 // число
for i < 100 {
isPrime := true
for j := 2; j < number; j++ {
if number%j == 0 {
isPrime = false
break
}
}
if isPrime {
arr[i] = number
i++
}
number++
}
fmt.Println(arr)
}
```
## Ключевое слово `range`
Для обхода массива необязательно заводить переменную-счетчик и проверять ее на равенство длине массива. Для этих целей удобно использовать цикл с `range`:
```go {.example_for_playground .example_for_playground_004}
arr := [3]string{"С", "Oberon", "Pascal"}
for key, val := range arr {
fmt.Println(key, ": ", val)
}
```
```
0 : С
1 : Oberon
2 : Pascal
```
Функция `range` возвращает два аргумента: ключ `key` и значение `val`. В данном случае ключ представляет собой индекс элемента массива, а `val` — значение элемента массива.
В Go, если какая-либо из возвращаемых переменных не нужна, вместо имени ставят пустой идентификатор `_`. Например:
```go {.example_for_playground .example_for_playground_005}
arr := [3]string{"С", "Oberon", "Pascal"}
for _, val := range arr {
fmt.Println(val)
}
```
```
С
Oberon
Pascal
```
В случае с range, если вторая переменная не нужна, то ее можно вообще не указывать:
```go {.example_for_playground .example_for_playground_006}
rooms := [5]string{"Ivan", "Nikolay", "Anna", "Viacheslav", "Petr"}
fmt.Println("Pepople with even room ids:")
for key := range rooms {
if key%2 == 0 {
fmt.Println(rooms[key])
}
}
```
## Многомерные массивы
Массивы могут быть многомерными. Вот как можно объявить двумерный массив (матрицу) из чисел типа `int` и задать элементу этой матрицы с индексами `2`, `3` значение `250`:
```go {.example_for_playground .example_for_playground_007}
var arr [4][5]int
arr[2][3] = 250
```
На практике обычно используется одномерные и двумерные массивы, в исключительных случаях — трехмерные. Использовать массивы большей размерности, без веских на то причин, не рекомендуется. Это усложняет программный код и чревато ошибками.
Объявите двумерный массив типа `int` размерностью `10x10` и задайте каждому его элементу значение, равное сумме индексов этого элемента. Например, для элемента с индексами `4` и `5` значение будет равно `4 + 5 = 9`. Выведите полученный массив в виде таблицы на экран, отделяя значения друг от друга символом табуляции `\t`. Последний элемент каждой строки таблицы символа табуляции содержать не должен. {.task_text}
```go {.task_source #golang_chapter_0040_task_0020}
package main
import "fmt"
func main() {
// ваш код здесь
}
```
Чтобы пройти по всем элементам двумерного массива, необходимо написать цикл в цикле. Внешний цикл осуществляет проход по строкам, внутренний - по столбцам. {.task_hint}
``` golang {.task_answer}
package main
import "fmt"
func main() {
var arr [10][10]int
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
arr[i][j] = i + j
if j == 9 {
fmt.Print(arr[i][j])
} else {
fmt.Print(arr[i][j], "\t")
}
}
fmt.Println()
}
}
```
Верхняя треугольная матрица (таблица) — матрица, у которой все элементы, стоящие ниже главной диагонали, равны нулю. Главная диагональ — набор элементов матрицы, взятый по диагонали от верхнего левого угла в направлении правого нижнего, т.е. таких элементов, для которых равны номер строки и номер столбца. {.task_text}
Объявите двумерный массив типа `int` размерностью `10x10` и задайте его элементам такие значения, чтобы получилась верхняя треугольная матрица. {.task_text}
Каждому ненулевому элементу этой матрицы задайте значение, равное сумме номеров этого элемента. Номера матрицы в линейной алгебре принято считать с единицы. Это нужно иметь в виду при вычислении суммы. Так, элемент в коде с индексами `[3][1]` должен быть равен `6`, потому что в линейной алгебре этот элемент имеет номера `[4][2]`. {.task_text}
Выведите полученный массив в виде таблицы на экран, отделяя значения друг от друга символом табуляции `\t`. Последний элемент каждой строки таблицы символа табуляции содержать не должен. {.task_text}
```go {.task_source #golang_chapter_0040_task_0030}
package main
import "fmt"
func main() {
// ваш код здесь
}
```
Если `i > j`, где `i` - индекс строки, а `j` - индекс столбца, то элемент находится ниже главной диагонали. {.task_hint}
``` golang {.task_answer}
package main
import "fmt"
func main() {
var arr [10][10]int
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
arr[i][j] = i + j + 2
if i > j {
arr[i][j] = 0
}
if j == 9 {
fmt.Print(arr[i][j])
} else {
fmt.Print(arr[i][j], "\t")
}
}
fmt.Println()
}
}
```
При работе с массивами нужно учитывать следующую особенность: передавая массив функции в качестве параметра, вы на самом деле передаете его копию, поэтому изменения внутри массива по выходу из этой функции будут потеряны.
Напоследок заметим, что массивы имеют недостатки:
- после того, как массив определен, вы не можете изменить его размер;
- передача массива в функцию всегда выполняется медленно, поскольку каждый раз создается копия этого массива.
Конечно, можно передать массив в функцию по указателю. Однако тип такого указателя зависит от размера массива, поскольку размер массива — часть его типа. Делать подобное неудобно.
Этих недостатков лишены срезы, о которых пойдет речь в следующей главе.
## Резюме
1. В Go используются массивы, которые могут быть как одномерными, так и многомерными.
2. Для обхода массива удобно использовать цикл с `range`.
3. Массивы обладают множеством недостатков, которых лишены срезы, поэтому массивы в Go используются достаточно редко.
Наша группа в telegram. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!