Golang 기초 (8) : 배열에 대하여

Eon Kim·2022년 1월 8일
0

Golang 기초 

목록 보기
8/14
post-thumbnail

안녕하세요, 주니어 개발자 Eon입니다.

이번 포스트는 배열에 관한 내용입니다.

📝 배열이란?

배열은 같은 타입을 가지는 변수들의 묶음입니다.
또, 선언된 변수들은 각각 연속된 메모리 공간에 할당됩니다.

배열은 수학의 행렬과 비슷하다고 볼 수 있습니다.
행과 열의 크기를 정하고, 그 안에 값을 저장합니다.

수학에서의 행렬

1 × 2 행렬

2 × 2 행렬


프로그래밍에서의 배열

1 × 2 의 형태는 1차원 배열

var a [2]int = [2]int{1, 2}

2 × 2 의 형태는 2차원 배열

var a [2][2]int = [2][2]int{{1, 2}, {3, 4}}


📝 배열의 구성

배열은 인덱스요소로 구성돼 있습니다.
인덱스 : 배열에 들어가 있는 각 요소들의 순서이며, 0부터 시작함
요소 : 각 인덱스가 가지는 값

배열 aint타입의 요소 4개로 이루어졌습니다.
요소인덱스 순서에 맞게 {1, 2, 3, 4}로 초기화합니다.
인덱스요소a[인덱스] = 요소로 나타낼 수 있습니다.



📝 선언

📌 지금까지의 변수 선언

var a int

위와 같이 int 타입의 변수 a를 선언했습니다.
여러 개의 변수를 선언하기 위해서는 아래와 같이 수행했습니다.

var a, b int

📌 배열의 선언

var a [5]int

위에서 int 타입의 변수 5개a라는 배열에 선언했습니다.
배열 a5개int 타입의 요소를 가집니다.

배열은 초기에 지정한 크기를 변경할 수 없습니다.
위의 예시에서 인덱스5개인 배열을 선언했는데, 이 배열의 크기는 4로 줄어들 수도, 6으로 늘어날 수도 없습니다.
때문에, 변수를 배열의 크기를 지정할 때 사용할 수 없고 상수는 사용이 가능합니다.



📌 여러 종류의 배열 선언 방법

배열을 선언하는 방법은 위에서 소개한 방법 외에도 몇 가지 더 있습니다.
위에서 소개한 방법을 포함해서 작성하겠습니다.

📍 var a [5]int // 초기화 없이 선언 & 값을 지정하는방법

각 요소에 개별적으로 값을 지정하는 방법

var a [5]int
a[0] = 1
a[1] = 2 
a[2] = 3 
a[3] = 4 
a[4] = 5 

위에서 소개한 방법입니다.
먼저 배열을 선언함과 동시에 각 요소에 개별적으로 접근하여 값을 지정했습니다.

값을 지정하지 않으면, 초기화를 하지 않았기에 a 안의 모든 요소의 값은 int타입의 zero-value인 0입니다.


📍 var a [5]int = [5]int{1, 2, 3, 4, 5} // 선언 & 초기화하는 방법

초기화와 동시에 배열에 통째로 값을 지정하는 방법

var a [5]int = [5]int{1, 2, 3, 4, 5}

참고 : golang go-static에서는 위와 같이 선언과 초기화를 같은 줄에 작성하는 걸 권장합니다.

var a [5]int = [5]int{1, 2, 3, 4}

인덱스5개인 배열에 값을 4개만 지정하는 경우, 초기화하지 않은 인덱스의 값은 zero-value가 됩니다.

fmt.Println(a[4])
// 0

📍 b := [3]bool{true, false, true} // 짧은 선언 & 초기화하는 방법

b := [3]bool{true, false, true}

위와 같이 짧은 선언과 초기화를 동시에 할 수 있습니다.


📍 var c = [5]float64{1: 1.1, 3: 3.3} // 인덱스를 지정하여 값을 초기화하는 방법

특정 인덱스에만 값을 초기화하는 방법

var c = [5]float64{1: 1.1, 3: 3.3}
var 배열이름 = [사이즈]타입{인덱스 : 요소, 인덱스 : 요소, ...}
fmt.Println(c)
// [0 1.1 0 3.3 0]

📍 d := [...]string{"one", "two", "three"} // 요소의 개수로 크기를 지정하는 방법

배열의 크기를 먼저 지정하지 않아도 되는 방법

d := [...]string{"one", "two", "three"}
fmt.Println(len(d))
// 3

len() 은 길이(length)를 반환하는 기본 내장함수입니다.
위에서 len()은 배열 d의 길이를 반환합니다.


📍 var mul [2][3]int = [2][3]int{{1, 2, 3}, {4, 5, 6}} // 다차원 배열 선언하는 방법

1. 한 줄에 선언 및 초기화

var mul [2][3]int = [2][3]int{{1, 2, 3}, {4, 5, 6}}

2. 여러 줄로 선언 및 초기화

var mul [2][3]int = [2][3]int{
	{1, 2, 3}, 
	{4, 5, 6},
}

이렇게 여러 줄로 초기화할 수 있습니다.
단, 새로 개행을 하고 괄호를 닫을 경우, 마지막 원소의 끝에 콤마(,)를 붙여야 합니다.



📌 다차원 배열은 언제 사용할까?

가장 쉬운 예시로, 차원을 표현할 때 사용할 수 있습니다.

📍 이미지 표현

이미지는 2차원입니다.
x, y축으로 이미지를 표현할 수 있습니다.
각 픽셀의 위치를 좌표로 하고, 그 위치에 들어가는 값으로 색을 정할 수 있습니다.

📍 3D 물체 표현

3D 물체는 3차원입니다.
x, y, z축으로 표현할 수 있습니다.
이미지와 마찬가지로 모든 좌표에 대하여 값을 넣음으로써 물체를 표현할 수 있습니다.



📌 배열의 순회

배열의 각 요소에 순차적으로 접근할 수가 있습니다.
앞서 반복문에 대한 포스트에서도 짧게 소개했습니다.

먼저 아래 배열 순회 예시에서 사용되는 배열 하나를 아래와 같이 선언하겠습니다.

var a [5]int = [5]int{1, 2, 3, 4, 5}

📍 for init; condition; post {...} : C-Like for

a[2] = 10
for i := 0; i < len(a); i++ {
	fmt.Printf("%d ", a[i])
}
// 1 2 10 4 5 

배열[인덱스] 로 원하는 인덱스 요소를 사용할 수 있습니다.
위와 같이 특정 인덱스의 값을 바꿀 수도 있습니다.


📍 for condition {...} : C-Like while

i := 0
for i < len(a) {
	fmt.Printf("%d ", a[i])
}
// 1 2 3 4 5 

📍 for {...} : C-Like for(;;)

i := 0
for {
	if i >= len(a) {
		break
	}
	fmt.Printf("%d ", a[i])
	i++
}
// 1 2 3 4 5 

📍 for - range : 'for loop' for array, slice, string, or map, or reading from a channel

for i, v := range a {
	fmt.Println("index : %d & value : %d", i, v)
}
/* The result of output
index : 0 & value : 0
index : 1 & value : 0
index : 2 & value : 0
index : 3 & value : 0
index : 4 & value : 0
*/

for i, v := range a {...} : i (index), v (value)가 들어갑니다.
이 루프 안에서는 a[i]를 사용하고 v를 사용하지 않아도 됩니다.
golang에서는 선언하고 사용하지 않는 변수가 있으면 컴파일 에러를 일으키기 때문에, a[i]로 사용하려면 아래와 같이 v를 선언하지 않으면 됩니다.
for i := range a {...}



📝 메모리 할당

📌 배열의 메모리 할당

배열을 선언하면 다른 변수와 마찬가지로 메모리에 공간이 할당됩니다.
아래 그림은 배열이 아닌 변수와 배열의 메모리 할당을 나타냅니다.

변수는 할당되면 그 변수 타입의 크기만큼 메모리 공간이 할당됩니다.
배열도 마찬가지입니다.
다만 배열은 맨 처음 인덱스를 기준으로 하여, 이어지는 인덱스는 전부 연속적인 메모리 공간에 할당됩니다.


위의 그림은 int32타입의 배열이므로, 각 인덱스의 주소값int32의 크기만큼의 차이를 둡니다.
0번 인덱스의 주소값100이라고 할 때, 1번 인덱스의 주소값은 100 + sizeOf(int32)가 됩니다.
(golang에서 sizeOf는 unsafe 패키지 내에 Sizeof() 함수로 사용할 수 있습니다. 다른 포스트에서 설명하겠습니다.)
32bit = 4byte 이므로, 각 인덱스의 주소값은 4바이트 단위로 증가합니다.
주소값 : 메모리 공간의 주소 (할당된 공간의 위치를 나타냄)



📌 다차원 배열의 메모리 할당

golang에서의 다차원 배열은, 메모리 영역 할당이 연속적입니다.

위와 같이 서로 떨어져 있는 메모리 영역에 공간을 할당받는 것이 아니라,
아래와 같이 연속된 메모리 영역에 공간을 할당받습니다.



📝 배열 복사

값의 복사는 쉽게 할 수 있습니다.


변수의 복사

var a, b int = 2, 3
a = b
fmt.Println(a)
// 3

위와 같이 변수에 값을 복사하는 것은 '대입'이라는 개념을 통해서 이해할 수 있습니다.
단, golang은 최강타입 언어라고 했습니다.
타입이나 크기가 다르면 값의 복사를 불허합니다.

var a int = 2
var b int64 = 3
a = b

위 과정은 에러가 발생합니다. 64비트 운영체제에서 사용해도 말입니다.
int는 64비트 운영체제에서 int64와 사이즈가 동일합니다.
하지만 타입명이 다릅니다. 그래서 에러가 발생합니다.


배열의 복사

var a [5]int = [5]int{1, 2, 3, 4, 5}
var b [5]int = [5]int{6, 7, 8, 9, 10}
a = b
fmt.Println(a)
// [6 7 8 9 10]

위의 경우엔 정상적으로 복사된 배열을 출력합니다.
배열의 타입과 크기가 모두 동일해서 가능했습니다.
여기서 타입이나 크기를 서로 다르게 지정을 한다면 복사가 불가능합니다.


이번 포스트는 배열에 대한 내용이었습니다.
감사합니다.👍

profile
주니어 개발자

0개의 댓글