포인터(pointer), & 연산자와 * 연산자
C 언어를 배우다 보면 빠지지 않고 등장하는 개념이 바로 포인터(pointer)인데요. 포인터는 처음엔 어렵게 느껴질 수 있지만, 메모리와 프로그램의 작동 방식을 더 깊이 이해하는 데 필수적인 개념이기도 합니다. 이번 포스팅에서는 포인터의 기초와 함께 & 연산자와 * 연산자의 역할, 배열과의 관계, 그리고 함수 호출 방식까지 차근차근 알아보겠습니다.
변수와 메모리 주소
우리가 변수를 선언하면, 컴퓨터는 해당 변수의 값을 저장하기 위해 메모리 공간을 할당하고 그 위치(주소)에 이름을 붙입니다.
int a = 10;
printf("%p\n", &a); // 변수 a의 메모리 주소 출력
위 예제에서 &a는 변수 a의 주소값을 의미하는데요. 주소는 %p 서식 지정자를 통해 출력할 수 있습니다.
포인터란?
포인터(Pointer)는 말 그대로 "어떤 값을 가리키는 변수"입니다. 구체적으로는 메모리 주소를 저장하는 변수이지요.
int a = 10;
int *p = &a; // 포인터 p는 변수 a의 주소를 저장
변수 선언 시 int *p;는 “p는 int형 데이터를 가리키는 포인터입니다”라는 의미인데요.
반면, 사용 중에 나오는 *p는 “포인터 p가 가리키는 주소에 있는 실제 값을 참조합니다”라는 의미가 됩니다.
printf("%d\n", *p); // 10 출력 (a의 값을 참조)
즉, * 기호는 선언 시에는 포인터 변수임을 나타내고, 사용 시에는 주소의 값을 가져오는 역할을 합니다.
& 연산자와 * 연산자
연산자 | 설명 |
& | 변수의 주소를 얻는 연산자 (address-of) |
* | 포인터가 가리키는 주소에 접근하는 연산자 (dereference) |
이 둘은 서로 반대 역할을 하며 함께 쓰일 때 진가를 발휘합니다.
배열과 포인터
배열은 내부적으로 연속된 메모리 공간에 데이터를 저장하므로, 포인터와 매우 밀접한 관계를 가집니다.
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr;
- 배열명 arr은 배열 첫 번째 요소의 주소를 의미합니다.
- 따라서 p[i]는 arr[i]와 동일하게 작동합니다.
- 또는 *(p + i)를 통해 i번째 요소에 접근할 수도 있습니다.
printf("%d\n", p[2]); // 30
printf("%d\n", *(p + 2)); // 30
함수 호출 방식: 값에 의한 호출 vs 참조에 의한 호출
함수에 인자를 전달하는 방법에는 두 가지가 있습니다.
값에 의한 호출 (Call by Value)
void modify(int x) {
x = 100;
}
int main() {
int a = 10;
modify(a);
printf("%d\n", a); // 여전히 10
}
- 이때에는 a의 값만 복사되어 함수로 전달되므로, 원본은 변하지 않습니다.
참조에 의한 호출 (Call by Reference)
void modify(int *p) {
*p = 100;
}
int main() {
int a = 10;
modify(&a);
printf("%d\n", a); // 100으로 변경됨
}
- 변수의 주소를 넘겨주면, 함수 안에서 원본 값을 직접 변경할 수 있습니다.
- 이때 매개변수는 포인터로 받아야 합니다.
'크래프톤 정글 > CS기초(키워드, 개념정리)' 카테고리의 다른 글
[CS기초] LCS(Longest common subsequence, 최장 공통 부분 수열) (0) | 2025.04.07 |
---|---|
[CS기초] 다이나믹 프로그래밍(DP, Dynamic Programming) (0) | 2025.04.07 |
[CS기초] B-tree (0) | 2025.04.02 |
[CS기초] 트라이(Trie) (0) | 2025.04.02 |
[중간정리] 3주차 - 동시성, DFS, 다익스트라, B-tree, 추상화 (0) | 2025.04.02 |