일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 30 | 31 |
- Babel
- Redis
- docker
- fastapi
- python
- React
- Switch
- CentOS
- For
- rabbitmq
- SQL
- linux
- php
- webpack
- Backbone.js
- AWS
- 블레이드 템플릿
- 기초 수학
- nginx
- Go
- NCP
- laravel
- Redux
- mariadb
- Node
- phpredis
- nodejs
- Machine Learning
- javascript
- deep learning
- Today
- Total
개발일기
Go - 포인터란 무엇인가 본문
1. 포인터란?
Go에서는 메모리의 주소값을 변수에 저장하는 포인터 변수를 직접 활용할 수 있도록 지원한다. 메모리 주소는 항상 16진수로 이루어지며 포인터 변수로 메모리 주소를 저장하면 0x 형식의 16진수로 값이 저장된다.
기존에 변수를 선언할 때는 변수명을 지정한 후, 변수값을 할당하여 변수를 선언하였다. 하지만 포인터를 선언할 때는, &와 * 연산자를 사용하여 변수값의 주소를 포인터에 저장시킨다.
2. 포인터 선언
var test *int // 포인터 선언
변수를 포인터로 선언할 때는 자료형 앞에 * 연산자를 붙이면 된다. 단순히 포인터 선언을 했을 경우에는 nil 값이 들어가게 된다. nil은 다른 언어들의 null과 같은 개념이다.
2-1. 메모리 할당
var test *int = new(int)
// var test *[자료형] = new(자료형)
nil값을 넣는 것이 아니라 메모리를 할당하기 위해서는 new() 연산자 안에 자료형을 적어주면 된다. 위와 같이 메모리를 할당한 후, fmt.Prinltn로 값을 출력해보면 0x~ 형식의 16진수 값이 출력되는 것을 확인할 수 있다. 이는 해당 메모리의 주소값으로써 실행될 때 마다 값이 변경된다. 매번 실행할 때 마다 랜덤의 메모리에 값을 할당하기 때문이다.
2-2. 포인터 값 대입
var standardVari int = 3 // 1. 일반 변수
var pointerVari *int = &standardVari // 2. 포인터 변수
fmt.Println(standardVari)
fmt.Println(pointerVari)
/*
실행 결과 :
3
0xc0000b6010 // 주소값은 실행될 때 마다 변경된다.
*/
첫번째는 일반 변수를 선언하는 방법이고 두번째는 변수를 포인터 변수에 대입하는 방법이다. standaradVari에는 3이라는 값이 들어있고, pointerVari에는 standardVari 변수의 주소값이 들어간다. 주소값은 실행할 때 마다, 매번 다르게 할당된다.
두 변수를 실행해보면 일반 변수는 값이 나오고, 포인터는 메모리 주소값이 나오는 것을 확인할 수 있다.
2-3. 포인터의 변수값 출력
var standardVari int = 3 // 1. 일반 변수
var pointerVari *int = &standardVari // 2. 포인터 변수
fmt.Println(standardVari)
fmt.Println(*pointerVari)
/*
실행 결과 :
3
3
*/
포인터로 선언된 pointerVari 변수 앞에 * 연산자를 붙인 후, 출력하면 메모리 주소 값이 나오는 것이 아니라 해당 변수의 메모리 주소가 아닌 메모리가 참조하고 있는 값이 출력된다.
3. 포인터의 예시
일반 변수를 파라미터로 한 함수를 호출 할 때는, 파라미터의 값은 함수가 종료되면 변경되지 않고 원래의 값으로 돌아오게 된다.
package main
import "fmt"
func fruitFunc(fruit string, price int) {
fruit = "mango"
price = 1000
fmt.Println("fruitFunc fruit : ", fruit)
fmt.Println("fruitFunc price : ", price)
}
func main() {
var fruit string = "orange"
var price int = 500
fruitFunc(fruit, price)
fmt.Println("main fruit : ", fruit)
fmt.Println("main price : ", price)
}
/*
실행 결과 :
fruitFunc fruit : mango
fruitFunc price : 1000
main fruit : orange
main price : 500
*/
fruitFunc함수에서 과일과 가격 파라미터 값을 각각 mango, price로 변경하였지만 함수 종료 후, main 함수에서 호출 했을 때는 main 함수에서 선언한 값이 출력되는 것을 확인할 수 있다. 함수의 파라미터로 값을 넘겨주었기 때문에 fruit과 price의 값이 변하지 않고 출력된다.
이때, 포인터를 사용하면 fruitFunc로 인해 main함수의 내용이 달라지도록 할 수 있다.
package main
import "fmt"
func fruitFunc(fruit *string, price *int) {
*fruit = "mango"
*price = 1000
fmt.Println("fruitFunc fruit : ", fruit)
fmt.Println("fruitFunc price : ", price)
}
func main() {
var fruit string = "orange"
var price int = 500
fruitFunc(&fruit, &price)
fmt.Println("main fruit : ", fruit)
fmt.Println("main price : ", price)
}
/*
실행 결과 :
fruit fruit : 0xc0001041e0
fruit price : 0xc000126010
main fruit : mango
main price : 1000
*/
fruitFunc에 포인터로 과일 이름과 가격 변수를 넘겨주었다. *fruit = "mango"와 *price="1000" 은 받아온 메모리 주소에 값을 대입해주는 것이기에 main함수의 변수 값에도 영향을 준다.
즉, 함수를 사용할 때 함수에 들어가는 파라미터의 값을 변경할 때 포인터를 유용하게 사용할 수 있다.
4. 주소값 변경
포인터는 16진수로 이루어져있다. 16진수의 값을 임의로 만들어 포인터 변수에 대입하여 메모리 주소를 직접 대입할 수 있을거라는 생각을 할 수 있다. 하지만 Go에서는 메모리 주소의 직접적인 대입은 허용되지 않는다.
package main
import "fmt"
func main() {
var test *int = new(int)
*test = 0xc000126010
fmt.Println(&test)
}
/*
실행 결과 :
0xc00000e028
*/
test변수에 16진수 값을 대입한 후, 메모리 주소 값을 출력했지만, 메모리 주소 값은 변경되지 않았다.
위의 경우는 메모리 주소값이 0xc00000e028로 설정되고 해당 메모리를 참조하는 변수의 값은 대입한 16진수인 0xc000126010로 대입되었다.
즉, Go에서는 메모리 주소의 직접적인 대입과 변경은 허용하지 않는다.
참고 사이트 :
https://towardsdev.com/when-and-where-to-use-pointers-in-go-7e89643a2c9
https://medium.com/@meeusdylan/when-to-use-pointers-in-go-44c15fe04eac
'프로그래밍 언어 > Go' 카테고리의 다른 글
Go - 인터페이스 선언 및 사용법 (0) | 2022.08.28 |
---|---|
Go - 구조체 선언 및 사용법 (0) | 2022.08.27 |
Go - panic() / recover() 예외처리 (0) | 2022.08.09 |
Go - defer 호출이란? (0) | 2022.08.07 |
Go - 함수의 정의 및 사용법 (0) | 2022.08.03 |