본문으로 바로가기

[Golang] 배열 (Array)

category Programming/Go 2022. 11. 12. 00:10

배열이란

배열은 같은 타입의 데이터들로 이루어진 타입이다.

  • 배열을 이루는 각 값은 요소(element)이다.
  • 요소를 가리키는 위치 값을 인덱스(index)라고 한다.

배열은 같은 타입의 여러 데이터를 하나의 변수로 효과적으로 사용할 수 있도록 해준다.

변수 선언 형식

var 변수명 [요소개수]타입
var t [5]float64

 

예제 1

package main

import "fmt"

func main() {
	var t [5]float64 = [5]float64{24.0, 25.9, 27.8, 26.9, 26.2} // ❶

	for i := 0; i < 5; i++ { // ❷
		fmt.Println(t[i]) // ❸
	}
}

---
24
25.9
27.8
26.9
26.2

배열 사용법

1️⃣ 배열 변수 선언 및 초기화

  • int 타입
    • int 타입 요소를 5개 갖는 배열 nums를 할당한다.
    • 초깃값을 지정하지 않아 각 요솟값은 int 타입의 기본값인 0으로 초기화 된다.
var nums [5]int

 

  • string 타입
    • string 타입 요소 3개를 갖는 배열 day를 할당한다.
days := [3]string{"monday", "tuesday", "wednesday"}
  • float64 타입
    • float64 타입 요소를 5개 갖는 배열 temps를 할당한다.
    • 첫 번째 두 번째 element는 각각 24.3과 26.7로 초기화 된다.
    • 나머지는 float64의 기본값인 0.0으로 초기화된다.
var temps [5]float64 = [5]float64{24.3, 26.7}
  • int 타입
    • int 타입 요소를 갖는 배열 s를 할당한다.
    • 인덱스가 1인 element를 10으로, 3인 element를 30으로 초기화한다.
    • 나머지는 int타입의 기본값인 0으로 초기화된다.
var s = [5]int{1:10, 3:30}
  • 배열 요소 개수 생략
    • … 를 사용하여 배열 요소 개수를 생략할 수 있다.
      • 배열 요소 개수는 초기화되는 요소의 개수와 같다.
    • 초기화 개수가 3개이므로 x의 요소는 3개가 되고 각각 10, 20, 30으로 초기화됨.
x := [...]int{10, 20, 30}

2️⃣ 배열 선언 시 개수는 항상 상수

배열 선언 시 개수는 항상 상수로 써야 한다.

  • 즉, 변숫값을 배열 개수로 사용하지 못함

예제

package main

const Y int = 3 // ❶ 상수

func main() {
	x := 5                     // ❷ 변수
	a := [x]int{1, 2, 3, 4, 5} // ❸

	b := [Y]int{1, 2, 3} // ➍

	var c [10]int // ➎
}
  • ❸에서 에러가 발생한다.
    • 변수로 선언한 x를 배열 길이로 사용하지 못한다.

3️⃣ 배열 요소 읽고 쓰기

배열 요소에 접근하고 값을 읽고 쓰려면 배열 변수에 대괄호 [ ]를 쓰고 그 사이에 접근하고자 하는 요소의 인덱스를 적는다.

예제

package main

import "fmt"

func main() {
	nums := [...]int{10, 20, 30, 40, 50} // ❶

	nums[2] = 300 // ❷

	for i := 0; i < len(nums); i++ { // ❸
		fmt.Println(nums[i]) // ➍
	}
}

4️⃣ range 순회

for 반복문에서 range 키워드를 이용하면 배열 요소를 순회할 수 있다.

package main

import "fmt"

func main() {
	var t [5]float64 = [5]float64{24.0, 25.9, 27.8, 26.9, 26.2} // ❶

	for i, v := range t { // ❷
		fmt.Println(i, v) // ❸
	}
}

---
0 24
1 25.9
2 27.8
3 26.9
4 26.2
  • ❷ range를 사용해 모든 배열 요소를 순회한다.
    • for문에서 i는 인덱스이고 v는 원솟값이다.

 

만약 인덱스가 필요 없고 요솟값만 필요하면 밑줄 _ 을 이용하여 인덱스를 무효화할 수 있다.

for _, v := range t {
		fmt.Println(v)
	}
}
💡 range 순회는 배열뿐만 아니라 문자열, 슬라이스, 맵, 채널 등에도 사용할 수 있다.

배열 is 연속된 메모리

  • 배열을 선언하면 컴퓨터에서는 연속된 메모리 공간을 확보한다.
    • ex) var a [10]int32 배열 선언 시 int32값 10개를 저장할 수 있는 연속된 메모리 공간을 찾아 할당함.
      • int32 타입은 4바이트이므로 연속된 40바이트를 찾아 할당한다.
  • 인덱스 요소를 찾아가는 방법은 배열의 시작 주소에 인덱스 * 타입 크기를 더해서 찾아간다.
요소 위치 = 배열 시작 주소 + (인덱스 * 타입 크기)

배열의 핵심

  • 배열은 연속된 메모리이다.
  • 컴퓨터는 인덱스 타입 크기를 사용하여 메모리 주소를 찾는다.

배열 복사

대입 연산자를 사용하여 배열 대 배열을 복사할 수 있다.

예제

package main

import "fmt"

func main() {
	a := [5]int{1, 2, 3, 4, 5}
	b := [5]int{500, 400, 300, 200, 100}

	for i, v := range a { // ❶ 배열 a 원소 출력
		fmt.Printf("a[%d] = %d\\n", i, v)
	}

	fmt.Println()         // ❷ 개행
	for i, v := range b { // ❸ 배열 b 원소 출력
		fmt.Printf("b[%d] = %d\\n", i, v)
	}

	b = a // ❹ a 배열을 b변수에 복사

	fmt.Println()         // 개행
	for i, v := range b { // ➎ 배열 b 원소 출력
		fmt.Printf("b[%d] = %d\\n", i, v)
	}
}
  • Go언어에서 대입 연산자는 우변의 값을 좌변의 메모리 공간에 복사한다.
    • 복사되는 크기는 타입의 크기와 같다.
  • b = a
    • a타입, b타입은 int 타입으로 요소당 8바이트씩, 총 40바이트이다.
    • a의 값은 변수 a가 가리키는 메모리 공간의 값, 즉 배열 전체를 뜻한다.
    • 그래서 Go언어에서 배열 간 대입은 전체 배열의 복사로 동작한다.

그러나 아래처럼 복사하려는 배열의 타입이 다르면 에러가 발생한다.

a := [5]int{1, 2, 3, 4, 5}
b := [5]float32{500, 400, 300, 200, 100}

b = a // error
  • Go언어에서 모든 연산자의 각 항의 타입은 항상 같아야 한다. 대입 연산자도 마찬가지이다.

다중 배열

배열은 이중 배열, 삼중 배열처럼 여러 번 중첩해서 사용 가능하다. 이를 다중 배열이라고 한다.

  • 이중 배열은 X, Y 좌표계의 위치 데이터들을 위해 주로 사용되어 이차원 배열이라고 부른다.
  • 삼중 배열은 삼차원 공간상의 좌표 데이터들을 위해 주로 사용되어 삼차원 배열이라고 부른다.

간단하게 다중 배열은 배열을 요소로 가지는 배열이라고 이해하면 쉽다.

 

초깃값 선언

배열에 초깃값을 넣는데 { } 를 사용한다. 이중 배열은 어떻게 할까?

var b = [2][5]int{
		{1, 2, 3, 4, 5},
		{6, 7, 8, 9, 10},
	}
⚠️ } (닫는 중괄호) 가 마지막 요소와 같은 줄에 있지 않으면 마지막 항목 뒤에 , 를 찍어줘야 한다.

예제

package main

import "fmt"

func main() {
	a := [2][5]int{ // ❶ 이중 배열 선언
		{1, 2, 3, 4, 5},
		{5, 6, 7, 8, 9}, // ❷ 여러 줄에 걸쳐 초기화할 때는 쉼표를 찍자!
	}
	for _, arr := range a { // ❸ arr값은 순서대로 a[0]의 배열 a[1]의 배열
		for _, v := range arr { // ❹ v값은 순서대로 a[0]과 a[1] 배열의 각 원소
			fmt.Print(v, " ") // ➎ v값 출력
		}
		fmt.Println()
	}
}
  • ❸ range 를 이용하여 a 배열 요소들을 순회한다.
    • 첫 번째 반복때는 a[0]
    • 두 번째 반복때는 a[1]
  • ❹ range를 이용하여 arr 배열 요소들을 순회한다.
    • 첫 번째 반복때는 a[0]의 모든 요소
    • 두 번째 반복때는 a[1]의 모든 요소

배열 크기

위에서 배열은 연속된 메모리 공간이라고 하였고 메모리 크기는 선언된 타입에 의해 결정된다고 했다.

그래서 배열 크기는 타입 크기 요소 개수가 된다.

배열 크기 = 타입 크기 * 항목 개수
  • [2][5]int의 이중 배열의 메모리 크기는 [5]int는 40바이트니까 2를 곱한 값인 80바이트이다.
  • 삼중도 마찬가지..
💡 배열을 이중, 삼중으로 선언하는 것은 프로그래머가 다루기 편함이다.
컴퓨터 입장에서는 [3][2][5]int나 [30]int이나 처리 하는 방법은 동일하다!
(단, 배열 내 요소에 접근할 때 [0][1][3]과 같이 여러 차수로 접근할 수 있느냐 [8]과 같이 하나의 차수로 접근하냐가 다르다.)

핵심 요약

  1. 배열은 값을 여러 개 저장하는 연속된 메모리 공간이다.
  2. 대괄호 [ ] 사이에 인덱스를 넣어서 배열 요소에 접근할 수 있다. a[3]은 a 배열에서 인덱스가 3인 요소에 접근한다.
  3. 배열의 인덱스는 0부터 시작한다.
  4. 내장 함수 len()으로 배열 길이를 알 수 있다.
  5. range를 이용하면 for문에서 배열을 순회할 수 있습니다.

 

'Programming > Go' 카테고리의 다른 글

[Golang] 포인터 (Pointer)  (0) 2022.11.13
[Golang] 구조체 (Structure)  (1) 2022.11.13
[Golang] for문  (0) 2022.11.11
[Golang] Switch문  (0) 2022.11.06
[Golang] if문  (0) 2022.11.06