포인터 (pointer) 이해하기

SEUNGJUN·2024년 4월 1일
0

CS

목록 보기
1/5

프로그래밍에서 중요한 개념 중 하나로, 메모리 주소를 가리키는 변수를 말한다. 이를 통해 변수나 데이터의 위치를 간접적으로 참조하거나 조작할 수 있다. 포인터는 프로그래밍 언어의 많은 기능과 기술적인 측면에서 중요한 역할을 한다.

* (역참조 연산자)

  • 포인터가 가리키는 메모리 주소에 저장된 값을 읽거나 수정할 때 사용된다.
  • 포인터 변수 앞에 *를 붙여 사용하며, 이를 통해 포인터가 가리키는 메모리에 접근할 수 있다.
  • 예를 들어, *ptr은 포인터 ptr이 가리키는 메모리의 값을 읽는다.
  • 역참조 연산자는 해당 주소에 접근하여 값을 읽거나 수정할 때 사용된다.

& (주소 연산자)

  • 변수의 메모리 주소를 구할 때 사용된다.
  • 변수 이름 앞에 &를 붙여 사용하며, 이를 통해 해당 변수의 메모리 주소를 얻을 수 있다.
  • 예를 들어, &var은 변수 var의 메모리 주소를 나타낸다.
  • 주소 연산자는 변수의 주소를 참조할 때 사용된다.

예를 들어서 삼겹살이라는 값을 어딘가에 두었다. 이때 그 주소가 컴퓨터에서 34524235라고 한다. 이때 &삼겹살34524235이고, *34524235삼겹살이 되는 것이다.

포인터의 역할

1. 동적 메모리 할당

  • 포인터를 사용하여 동적으로 메모리를 할당하고 해제할 수 있다. 동적 메모리 할당은 프로그램이 실행 중에 필요한 메모리를 동적으로 할당하여 사용할 수 있게 해준다. 예를 들어, 배열의 크기를 실행 중에 결정하거나, 복잡한 데이터 구조를 생성할 때 포인터가 필요하다.

2. 데이터 구조와 동적 데이터 구조

  • 포인터를 사용하여 다양한 데이터 구조를 구현할 수 있다. 연결 리스트, 트리, 그래프 등의 동적 데이터 구조를 구현하는 데 포인터가 필수적으로 사용된다.

3. 함수와 메모리 관리

  • 포인터를 사용하여 함수에 데이터를 전달하거나 반환할 수 있다. 또한 포인터를 사용하여 함수 내부에서 메모리를 효율적으로 관리하고 데이터를 조작할 수 있다. 이는 효율적인 알고리즘 및 데이터 구조를 구현하는 데 도움이 된다.

4. 저장 공간의 효율적 사용

  • 포인터를 사용하여 메모리를 효율적으로 사용할 수 있다. 예를 들어, 큰 데이터 구조를 복사하는 대신 포인터를 사용하여 데이터의 주소만 복사할 수 있다.

5. 저수준 프로그래밍

  • 포인터는 메모리 주소를 직접 조작할 수 있기 때문에 하드웨어와 더 밀접한 상호작용이 필요한 저수준 프로그래밍(예: 임베디드 시스템 프로그래밍)에 필요하다.

포인터의 종류

1. 일반 포인터 (Generic Pointer)

  • EX) void* ptr;
  • 일반 포인터는 데이터 타입에 관계없이 어떠한 유형의 데이터든 가리킬 수 있는 포인터, void* 타입은 어떤 데이터 타입의 주소도 가리킬 수 있으므로, 다양한 유형의 데이터를 가리키기 위해 사용된다.

2. 포인터 상수 (Pointer Constant)

  • EX) int* const ptr;
  • 포인터 상수는 포인터 변수를 가리키는 포인터 상수로, 한 번 할당되면 다른 메모리 주소를 가리키지 않는다. const 한정자를 사용하여 선언되므로, 한 번 포인터가 가리키는 주소가 설정되면 그 주소를 변경할 수 없다.

3. 상수 포인터 (Constant Pointer)

  • EX) const int* ptr;
  • 상수 포인터는 포인터가 한 번 가리키는 주소를 변경하지 못하게 하는 포인터, const 한정자를 사용하여 선언된 변수를 가리킨다. 따라서 포인터가 가리키는 값은 변경할 수 있지만, 포인터가 가리키는 주소는 변경할 수 없다.

4. 포인터 배열 (Pointer Array)

  • EX) int* arr[5];
  • 포인터 배열은 포인터들의 배열이다. 각 요소는 포인터로, 각 포인터는 다른 메모리 주소를 가리킬 수 있다. 포인터 배열은 일반적으로 다수의 데이터나 문자열을 가리키는데 사용된다.

5. 배열 포인터 (Array Pointer)

  • EX) int (*ptr)[5];
  • 배열을 가리키는 포인터이다. 배열의 첫 번째 요소를 가리키며, 포인터 산술을 통해 배열의 요소에 접근할 수 있습니다. 배열 포인터는 다차원 배열이나 배열의 일부를 가리키는데 사용된다.

6. 이중 포인터 (Double Pointer)

  • EX) int** ptr;
  • 이중 포인터는 포인터를 가리키는 포인터이다. 즉, 이중 포인터는 메모리의 주소가 아니라 다른 포인터 변수를 가리킨다. 이중 포인터는 포인터의 포인터이며, 주로 메모리 할당과 관리를 위해 사용된다.

7. 함수 포인터 (Function Pointer)

  • EX) int (*ptr)(int, int);
  • 함수를 가리키는 포인터이다. 함수의 주소를 가지며, 해당 주소로 이동하여 함수를 호출할 수 있다. 함수 포인터는 함수를 동적으로 호출하거나 다른 함수에 함수 포인터를 전달할 때 사용된다.

EX) 예시

(1)

#include <stdio.h>

void main()
{
	char *p = "KOREA" --------- A
    printf("%s\n" , p); ------- B
    printf("%s\n" , p+3); ----- C
    printf("%c\n" , *p); ------ D
    printf("%c\n" , *(p+3)); -- E
    printf("%c\n" , *p+2); ---- F
}
  • A - 문자열 "KOREA"의 첫 번째 문자인 "K"의 주소를 포인터 p에 저장한다.

  • B -포인터 p가 가리키는 위치부터 널 문자('\O')를 만날 때까지 문자열을 출력한다. 따라서 "KOREA" 가 출력된다.

  • C - 포인터 p에 3을 더하여 포인터 산술을 수행한다. 포인터 p가 현재 가리키는 문자열에서 3번째 위치인 'E'의 주소로 이동하게 된다. 따라서 "EA"가 출력된다.

  • D - 포인터 p가 가리키는 위치에 있는 값을 출력한다. 포인터 p는 문자열 "KOREA"의 첫 번째 문자 'K'의 주소를 가리키므로 'K'가 출력된다.

  • E - 포인터 p에 3을 더하여 포인터 산술을 수행한다. 이는 포인터 p가 현재 가리키는 문자열에서 3번째 위치인 'E'의 주소로 이동한 후 해당 위치에 있는 값을 출력한다. 따라서 'E'가 출력된다.

  • F - 포인터 p가 가리키는 위치에 있는 값을 읽어온 후 2를 더하여 해당 값의 ASCII 코드에 따라 문자를 출력한다. 포인터 p가 가리키는 값은 'K'이며, 'K'의 ASCII 코드는 75이므로, 따라서 'K'의 ASCII 코드에 2를 더한 값인 77에 해당하는 문자 'M'이 출력된다.

(2)

#include <stdio.h>

int main() {
    int a = 10, b = 20, c = 30;
    int* p[3] = {&a, &b, &c}; ---------A
    
    printf("%d\n", *p[0]); ------------B
    printf("%d\n", *p[1]); ------------C
    printf("%d\n", *p[2]); ------------D
    
    printf("%d\n", **(p+0)); ----------E
    printf("%d\n", **(p+1)); ----------F
    printf("%d\n", **(p+2)); ----------G
    return 0;
}
  • A - int형 포인터 배열 p를 선언하고 각 요소를 a, b, c의 주소로 초기화한다.
  • B - 포인터 배열 p의 첫 번째 요소가 가리키는 값, 즉 a의 값인 10을 출력합니다.
  • C - 포인터 배열 p의 두 번째 요소가 가리키는 값, 즉 b의 값인 20을 출력합니다.
  • D - 포인터 배열 p의 세 번째 요소가 가리키는 값, 즉 c의 값인 30을 출력합니다.
  • E - 포인터 배열 p의 첫 번째 요소의 값을 간접 참조하여 출력합니다. p+0은 첫 번째 요소를 가리키므로 **(p+0)은 p[0]과 동일하게 a의 값을 출력합니다.
  • F - 포인터 배열 p의 두 번째 요소의 값을 간접 참조하여 출력합니다. p+1은 두 번째 요소를 가리키므로 **(p+1)은 p[1]과 동일하게 b의 값을 출력합니다.
  • G - 포인터 배열 p의 세 번째 요소의 값을 간접 참조하여 출력합니다. p+2는 세 번째 요소를 가리키므로 **(p+2)은 p[2]와 동일하게 c의 값을 출력합니다.
profile
RECORD DEVELOPER

0개의 댓글