배열 (Array) .1
배열이란 연관된 데이터를 하나의 변수에 그룹핑해서 관리하기 위한 방법이다.
배열의 선언 방법
var 배열명 [배열수] 데이터타입 {1,2,3,..}
A := [배열수] 데이터타입 {1,2,3,...}
ex1)
package main
import "fmt"
func main() {
var A [10]int
for i := 0; i < len(A); i++ { // 배열 (A) 의 length 길이가 들어가게 된다.
A[i] = i * i
}
fmt.Println(A)
}
--------------------------------
[0 1 4 9 16 25 36 49 64 81]
배열의 특징
문자열 배열은 기본 byte배열(==uint8 0~255)
ASCII 코드: 모든 코드가 1byte
UTF-8 : 영어,빈칸,기호 1byte 나머지 2~3byte
ex2)
package main
import "fmt"
func main() {
s := "Hello World"
for i := 0; i < len(s); i++ {
fmt.Print(s[i], ",")
}
}
---------------------------------
72,101,108,108,111,32,87,111,114,108,100, // 각 문자에 해당하는 코드가 나온다.
ex3)
package main
import "fmt"
func main() {
s := "Hello World"
for i := 0; i < len(s); i++ {
fmt.Print(string(s[i]), ",")
} // string으로 문자를 표현한다.
}
---------------------------------
H,e,l,l,o, ,W,o,r,l,d,
ex4) 한글의 경우
package main
import "fmt"
func main() {
s := "Hello 월드"
for i := 0; i < len(s); i++ {
fmt.Print(string(s[i]), ",")
}
}
---------------------------------
H,e,l,l,o, ,ì,,ë,,, //한글은 3바이트 3가지 코드가 합쳐져서 만들어 졌기 때문에 문자열 배열에 들어가게 되면 각 byte들이 나오게 되어 글자가 깨져서 나오게 된다.
ex5) 한글의 코드
package main
import "fmt"
func main() {
s := "Hello 월드"
for i := 0; i < len(s); i++ {
fmt.Print(s[i], ",") // 코드를 출력 했을때
}
}
------------------------------------
72,101,108,108,111,32,236,155,148,235,147,156, // 8개가 아닌 12개의 코드가 나온걸 볼 수 있다.
문자열(string)은 byte배열로 나타낼 수 있지만 rune배열로도 나타낼 수 있다.
rune: 고랭의 변수 데이터타입 중 하나로 UTF-8을 나타내는 타입이다. 그렇기 때문에 타입의 길이는 1 ~ 3byte로 어떤 문자냐에 따라서 길이가 변한다.
ex6)
package main
import "fmt"
func main() {
s := "Hello 월드"
s2 := []rune(s) //데이터 타입을 rune으로 설정하고 s를 넣음
fmt.Println("len(s2) = ", len(s2))
for i := 0; i < len(s2); i++ {
fmt.Print(s2[i], ", ")
}
}
-------------------------------
len(s2) = 8
72, 101, 108, 108, 111, 32, 50900, 46300, // byte와 달리 8개가 나옴
ex7)
package main
import "fmt"
func main() {
s := "Hello 월드"
s2 := []rune(s)
fmt.Println("len(s2) = ", len(s2))
for i := 0; i < len(s2); i++ {
fmt.Print(string(s2[i]), ", ")
} // 문자열로 표현해 보았을때
}
---------------------------
len(s2) = 8
H, e, l, l, o, , 월, 드,
배열 (Array) .2
ex1)
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
clone := [5]int{}
for i := 0; i < 5; i++ {
clone[i] = arr[i] // clone에 arr의 배열을 초기화 시킴
}
fmt.Print(clone)
}
-----------------------------
[1 2 3 4 5]
ex2) 두번 복사
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5} //1~5까지 순서대로
temp := [5]int{}
for i := 0; i < len(arr); i++ {
temp[i] = arr[len(arr)-1-i]
} // temp에다가 arr[4]~ arr[0]까지 역순으로 집어넣음
for i := 0; i < len(arr); i++ {
arr[i] = temp[i]
} //역순으로 집어넣은걸 다시 arr에 집어넣음
fmt.Println("temp:", temp)
fmt.Println("arr:", arr)
}
----------------------------
temp: [5 4 3 2 1]
arr: [5 4 3 2 1]
ex3) 복사를 사용하지 않고
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
for i := 0; i < len(arr)/2; i++ {
arr[i], arr[len(arr)-1-i] = arr[len(arr)-1-i], arr[i]
} // arr[0],arr[4] = 5, 1 이라는 의미
fmt.Println(arr)
}
----------------------------
[5 4 3 2 1]
복사를 두번한 경우: for문 2번 사용하여 총 길이에 2배가 되어 처리 속도가 느림
복사를 사용하지 않은 경우: 1/2 만큼 for문을 돌려서 처리 속도가 비교적 빠름
정렬은 배열에 숫자가 무작위로 들어가 있을 경우 숫자를 순서대로 정렬하는 것을 말한다.
알파벳도 가능
임시 배열(temp)을 하나 생성한 후 정렬을 원하는 배열(arr)의 랜덤한 숫자의 순서를 정렬 시키고, 만약 같은은 수가 있으면 갯수를 세아린 후 순서대로 arr에 집어 넣어 정렬 시킨다.
특징
특정 조건에서만 사용되어 질 수 있다.
원소의 값의 범위가 제한되어 있어야 한다.
똑같은 메모리의 배열을 또하나 만들기 때문에 배열 원소의 범위가 작아야한다.
ex1) Radix Sort
package main
import "fmt"
func main() {
arr := [11]int{0, 5, 4, 9, 5, 4, 3, 2, 1, 9, 5}
temp := [10]int{}
for i := 0; i < len(arr); i++ {
idx := arr[i] // arr[i] 에 해당하는 값을 idx로 한다
temp[idx]++ // 각 원소 들이 몇번 나오는지 횟수를 저장한다.
}
idx := 0 // 현재 인덱스
for i := 0; i < len(temp); i++ { // temp의 갯수 10만큼 돈다
for j := 0; j < temp[i]; j++ { //temp에 저장된 숫자 = 갯수 이므로 그 숫자 만큼 반복한다.
arr[idx] = i
idx++ // idx 0 부터 증가시켜 숫자를 정렬 시킴
}
}
fmt.Println(arr)
}
---------------------------
[0 1 2 3 4 4 5 5 5 9 9]
structure
변수들을 하나로 묶어서 관리하기 쉽게 해줘서 응집성을 올려준다.
구조체 선언방법
type 구조체명 struct {
변수명 타입
변수명 타입
}
ex1) 기본형태
package main
import "fmt"
type Person struct {
name string
age int
} // name, age 변수를 구조체로 만듦
func main() {
var p Person
p1 := Person{"개똥이", 15}
p2 := Person{name: "소똥이", age: 21}
p3 := Person{name: "Carson"}
p4 := Person{}
fmt.Println(p, p1, p2, p3, p4)
p.name = "Smith" //변수에 "."을 찍어서 불러 올 수 있다.
p.age = 24
fmt.Println(p)
}
----------------------------
{ 0} {개똥이 15} {소똥이 21} {Carson 0} { 0}
{Smith 24}
ex2) 기능(method) 추가
package main
import "fmt"
type Person struct {
name string
age int
}
func (p Person) PrintName() { // Person 이라는 객체에 PrintName이라는 기능을 추가한다.
fmt.Print(p.name)
}
func main() {
var p Person
p.name = "Smith"
p.age = 24
fmt.Println(p)
p.PrintName() // 매소드 호출
}
---------------------------------
{Smith 24}
Smith
ex3) 성적 조회
package main
import "fmt"
type Student struct {
name string
class int
grade Grade // grade에 Grade라는 타입을 설정해줌
}
type Grade struct {
name string
grade string
}
func (s Student) ViewGrade() { // Student의 기능 ViewGrade로 성적 조회가 가능한 기능
fmt.Println(s.grade)
}
func (s Student) Studentinfo() {
fmt.Println(s.name, s.class, "반")
} // 이름과 반을 출력해주는 기능
func main() {
var s Student
s.name = "철수"
s.class = 1
s.grade.name = "수학"
s.grade.grade = "C"
s.Studentinfo()
s.ViewGrade()
}
--------------------------
철수 1 반
{수학 C}
포인터
포인터는 변수가 가지는 메모리의 주소를 가르킨다.
*go언어에서는 c,c++ 과는 다르게 연산이나 캐스팅을 막아놓았다.
포인터 선언
var a *int //타입에 *을 붙여서 선언한다
ex1)
package main
import "fmt"
func main() {
var a int
var b int
var p *int // *로 포인터 변수를 선언
a = 3
b = 2
p = &a // &로 주소값을 받는다.
fmt.Println(a)
fmt.Println(p) // p 는 a의 주소를 받았기 때문에 주소가 나옴
fmt.Println(*p) // *p를 하면 p가 받은 주소에 저장된 값이 나옴
p = &b // b의 주소를 받음
fmt.Println(b)
fmt.Println(p)
fmt.Println(*p)
}
------------------------------------------
3
0xc0000aa058
3
2
0xc0000aa070
2
ex2) 포인터를 사용하지 않았을 때
package main
import "fmt"
func main() {
var a int
a = 1
Increase(a) // 함수로 a 의 값을 줌
fmt.Println(a) //함수에 들어갔다 나온 값을 출력함
}
func Increase(x int) {
x++ // 인자로 받은 값을 증가 시켜줌
}
---------------------------
1 // 증가되지 않은 것을 알 수 있음
x란 변수는 a로부터 받은 값을 복사해서 가지고 있기 때문에 x를 증가 시켜도 a는 변하지 않음
ex3) 포인터를 사용하였을 때
package main
import "fmt"
func main() {
var a int
a = 1
Increase(&a) // 함수로 a의 주소를 넘겨줌
fmt.Println(a)
}
func Increase(x *int) { // x는 포인트 변수로 a에서 받은 주소를 저장함
*x++ //해당 주소에 저장된 값에 1을 더함
}
--------------------------------
2 // a의 값이 증가 된 것을 알 수 있다.
ex4) 포인터를 사용하지 않았을 때
package main
import "fmt"
type Student struct {
name string
age int
grade string
class string
} // 변수들이 포함된 구조체를 만듦
func (a Student) PrintSungjuk() {
fmt.Println(a.class, a.grade)
} // Student에 포함된 class와 grade을 출력해주는 메소드를 만듦
func (b Student) InputSungjuk(class string, grade string) {
b.class = class
b.grade = grade
} // Student에 포함된 성적을 입력하는 메소드를 만듦
func main() {
var s Student = Student{name: "jinsoo", age: 23, class: "수학", grade: "F"} //구조체를 통해 값을 입력
s.InputSungjuk("과학", "C") // 성적입력 메소드를 통해 입력 값을 변경
s.PrintSungjuk() //성적 출력 메소드로 성적을 출력한다.
}
------------------------
수학 F // 성적 입력 메소드로 입력 값을 변경했지만 s 값은 변경 되지 않았다.
ex5) 포인터를 사용하였을 때
package main
import "fmt"
type Student struct {
name string
age int
grade string
class string
}
func (a *Student) PrintSungjuk() {
fmt.Println(a.class, a.grade)
} // a 를 포인터 변수로 설정
func (b *Student) InputSungjuk(class string, grade string) {
b.class = class
b.grade = grade
} // b 를 포인터 변수로 설정
func main() {
var s Student = Student{name: "jinsoo", age: 23, class: "수학", grade: "F"}
s.InputSungjuk("과학", "C")
s.PrintSungjuk()
}
--------------------------------
과학 C
*구조체를 호출 하면 구조체 안에있는 변수들이 다 같이 복사되기 때문에 메모리에 낭비가 크지만 포인터 형태로 호출하게 되면 주소만 저장되기 때문에 메모리의 낭비를 줄일 수 있다.