프로그래밍에서 중요한 개념 중 하나로, 메모리 주소를 가리키는 변수
를 말한다. 이를 통해 변수나 데이터의 위치를 간접적으로 참조하거나 조작할 수 있다. 포인터는 프로그래밍 언어의 많은 기능과 기술적인 측면에서 중요한 역할을 한다.
*
(역참조 연산자)
- 포인터가 가리키는 메모리 주소에 저장된 값을 읽거나 수정할 때 사용된다.
- 포인터 변수 앞에
*
를 붙여 사용하며, 이를 통해 포인터가 가리키는 메모리에 접근할 수 있다.
- 예를 들어,
*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의 값을 출력합니다.