Skip to content

Latest commit

 

History

History
143 lines (117 loc) · 6.29 KB

pointer.md

File metadata and controls

143 lines (117 loc) · 6.29 KB

Pointer

pointer

Go언어에는 C, C++ 처럼 포인터가 있다. 포인터는 변수이다. 하지만 특별한 변수이다.

  • 포인터는 메모리 주소만을 저장하기 위해 만들어진 특별한 변수이다.
  • 포인터 변수에는 메모리 주소만 저장된다.
// 포인터 변수는 메모리 주소만 저장 가능
  var pp *int
  pp = 1          // 포인터 변수에 정수 할당 시도
  fmt.Println(pp) // cannot use 1 (type int) as type *int in assignment

pp는 포인터변수 이기에 메모리 주소만 할당 가능하다. pp = 1 을 통해 정수를 할당하려고 하였으나 오류를 만나게 된다.

  • 자신이 사용하고자 한는 메모리의 '주소값'을 포인터 변수를 통해 저장할 수 있다.

포인터는 메모리의 주소(위치)를 담고 있다.

  • 포인터 값 == 변수의 주소
// 주소의 예
0xc000096040
  • 포인터를 잘 이해하기 위해서는 메모리가 구성되고 관리되는 방법을 알아야 한다.

    • Static, Global
    • Automatic, Local
    • Dynamic
    • Scope
    • Lifetime
      메모리의 종류를 이해하는 것이 포인터의 동작을 이해하는데 도움이 된다.
  • 모든 값이 주소를 갖고있지는 않더라도 모든 변수에는 주소가 있다.

    • Struct의 field, Array의 element도 변수이기 때문에 주소를 갖고 있다.

Pointer의 특징

  • 참조 Reference
    &<pointerName>

    • &연산자는 단항 연산자이며 변수만을 피연산자(operand)로 사용한다.
  • 역참조 Dereference
    *<pointerName>

    • 포인터변수에 값을 대입할 때 사용
    • 포인터변수의 값을 가져올 때 사용
  • Pointer의 제로값은 어느 Type이던지 nil 이다.

    • 포인터 변수를 선언하면 nil로 초기화 된다.
    • nil pointer은 아무 주소도 참조하고 있지 않은 포인터를 말한다.
      • 포인터 변수 p 가 있고 p != niltrue 라는 것은 p가 이미 특정 변수를 가리키고 있다는 것을 의미.
  • 포인터 연산 불가

    • Go언어에서는 메모리 주소를 연산하여 직접 다룰 수 없다.
  • Pointer 끼리는 비교할 수 있다.

    • 비교연산자(==) 를 사용한다.
    • 참인 경우
      그 외에는 모두 false
      • 두 포인터가 동일한 변수를 가리킴.
      • 두 포인터가 제로값인 nil을 가짐.
  • * (Asterisk)를 자료형 앞에 붙인다.

    • C, C++ 인 경우 * 는 자료형 뒤에 온다.
  • new() 함수를 통해 메모리를 할당한다.

    • new() 함수는 지정한 자료형의 크게에 맞는 메모리 공간을 할당해준다.
  • Garbage Collection 지원.

    • Go언어는 가비지 컬렉션을 지원해준다. 그로인해 메모리 해제는 신경쓰지 않고 메모리 할당에만 신경쓰면 된다.
      • C/C++ 같은 경우 프로그래머가 직접 free()/ delete() 함수를 통해 메모리 해제를 해주어야 한다.

Pointer expressions

Syntax

  • 포인터 변수 선언
    var <pointerName> *Type
var p *int                        
  fmt.Println("p", p)                            // <nil>
  fmt.Println("Type of p : ", reflect.TypeOf(p)) // *int

p라는 포인터변수를 선언만 해 주었기 때문에 Go 컴파일러가 해당 값을 nil 로 설정해 주었다.

  • C언어의 NULL 값이 Go언어에서는 nil 이다.

    • C에서 NULL은 정수 0이지만 Go에서의 nil 은 숫자 0이 아니다.
      즉, fmt.Println(nil == 0)은 compiler error를 낸다.
  • new() 함수
    var <pointerName> *Type = new(Type)
    var <pointerName> = new(Type)

var p1 *int
  var p2 *int = new(int)
var p3 = new(int)

  fmt.Println(p1) // <nil>
  fmt.Println(p2) // 0xc000096038
fmt.Println(p3) // 0xc000096040

p1은 선언만 한 포인터변수 이기에 초기값으로 nil 이 할당됬다.
p2는 new() 함수를 통해 선언과 동시에 메모리를 할당. 메모리 값으로 0xc000096038 이 할당되었다.
메모리 주소는 시스템마다 다며 컴파일 할 때 마다 달라진다.

  • dereference | 역참조
    역참조를 사용하여 메모리 주소의 값을 대입하거나 가져올 수 있다.
    *<pointerName>
    *<pointerName> = values

    var numPtr *int = new(int)
    fmt.Println(numPtr) // 0xc00009690
    //dereference
    *numPtr = 2020
    fmt.Println(*numPtr) // 2020
    • 변수를 선언할 때 * 를 붙이면 포인터형 변수가 되지만,
      변수를 사용할 때 * 를 붙이면 역참조가 된다.
  • reference | 참조
    일반 변수에 참조(&)를 사용하면 포인터형 변수에 대입할 수 있다.

    // reference &
    var n int = 2020   // 일반 변수 n
    var nPtr *int = &n // 참조로 n 변수의 메모리 주소를 구한 후, 포인터 변수 nPtr에 대입
    fmt.Println(n)     // 2020
    fmt.Println(&n)    // 0xc000096048
    fmt.Println(nPtr)  // 0xc000096048

    변수 앞에 & 를 붙이면 해당 변수의 메모리 주소를 뜻한다.
    즉, var nPtr *int = &n 는 일반변수 n 의 주소 자체를 포인터변수 nPtr 의 값으로 할당해 준 것.

  • 포인터 직접 다루기 불가
    Go언어의 포인터는 직접 다룰 수 없다.

    • 메모리 주소를 직접 대입할 수 없음.
    • 포인터 연산을 할 수 없음
      // Go 언어에서는 Pointer연산을 지원하지 않는다.
      var numPtr4 *int = new(int)
      numPtr4++              // 연산시도 --> invalid operation: numPtr4++ (non-numeric type *int)
      numPtr4 = 0xc0820062d0 // cannot use 826814784208 (type int) as type *int in assignment