C언어 강의 8편: 포인터 기초
· 4분 읽기
C언어 강의 8편: 포인터 기초
포인터란?
포인터(Pointer)는 변수의 메모리 주소를 저장하는 변수입니다. C언어의 가장 강력하면서도 어려운 개념 중 하나입니다.
메모리 주소 이해하기
모든 변수는 메모리에 저장되며, 각각 고유한 주소를 가집니다:
int num = 10;
printf("값: %d\n", num); // 10
printf("주소: %p\n", &num); // 메모리 주소 (예: 0x7fff5fbff6ac)
&: 주소 연산자 (Address Operator)- 변수 앞에
&를 붙이면 그 변수의 주소를 얻을 수 있습니다
포인터 선언
데이터타입 *포인터변수명;
예시
int num = 10;
int *ptr; // int형 포인터 선언
ptr = # // num의 주소를 ptr에 저장
printf("num의 값: %d\n", num); // 10
printf("num의 주소: %p\n", &num); // 주소
printf("ptr이 가리키는 값: %d\n", *ptr); // 10
printf("ptr에 저장된 주소: %p\n", ptr); // &num과 동일
역참조 연산자 (*)
포인터가 가리키는 메모리의 값을 가져오거나 변경할 수 있습니다:
int num = 10;
int *ptr = #
*ptr = 20; // ptr이 가리키는 곳(num)의 값을 20으로 변경
printf("%d\n", num); // 20
포인터의 기본 사용법
#include <stdio.h>
int main() {
int num = 10;
int *ptr = #
printf("=== 포인터 기본 ===\n");
printf("num의 값: %d\n", num);
printf("num의 주소: %p\n", &num);
printf("ptr의 값(주소): %p\n", ptr);
printf("ptr이 가리키는 값: %d\n", *ptr);
// 포인터를 통한 값 변경
*ptr = 20;
printf("\n값 변경 후:\n");
printf("num의 값: %d\n", num);
printf("ptr이 가리키는 값: %d\n", *ptr);
return 0;
}
포인터와 함수
포인터를 사용하면 함수에서 실제 변수의 값을 변경할 수 있습니다:
값에 의한 전달 (Call by Value)
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
// 함수 내에서만 값이 바뀜
}
int main() {
int x = 10, y = 20;
swap(x, y);
printf("%d %d\n", x, y); // 10 20 (변하지 않음)
return 0;
}
참조에 의한 전달 (Call by Reference)
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
swap(&x, &y);
printf("%d %d\n", x, y); // 20 10 (값이 바뀜)
return 0;
}
포인터와 배열
배열 이름은 첫 번째 요소의 주소를 가리킵니다:
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // arr은 &arr[0]과 동일
printf("%d\n", *ptr); // 1 (arr[0])
printf("%d\n", *(ptr + 1)); // 2 (arr[1])
printf("%d\n", *(ptr + 2)); // 3 (arr[2])
// 배열 접근 방법들
printf("%d\n", arr[0]); // 1
printf("%d\n", *(arr + 0)); // 1 (동일)
printf("%d\n", ptr[0]); // 1 (동일)
포인터 산술 연산
포인터에 정수를 더하거나 빼면 다음/이전 요소를 가리킵니다:
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr;
printf("%d\n", *ptr); // 10
printf("%d\n", *(ptr + 1)); // 20
printf("%d\n", *(ptr + 2)); // 30
ptr++; // 다음 요소로 이동
printf("%d\n", *ptr); // 20
NULL 포인터
포인터가 아무것도 가리키지 않을 때 사용:
int *ptr = NULL;
if (ptr == NULL) {
printf("포인터가 NULL입니다.\n");
}
// NULL 포인터 역참조는 위험!
// *ptr = 10; // 오류 발생!
포인터의 포인터 (이중 포인터)
포인터의 주소를 저장하는 포인터:
int num = 10;
int *ptr = #
int **pptr = &ptr;
printf("num: %d\n", num); // 10
printf("*ptr: %d\n", *ptr); // 10
printf("**pptr: %d\n", **pptr); // 10
동적 메모리 할당
포인터를 사용하여 런타임에 메모리를 할당할 수 있습니다:
#include <stdlib.h>
int main() {
int *ptr;
int n = 5;
// 동적 메모리 할당
ptr = (int*)malloc(n * sizeof(int));
if (ptr == NULL) {
printf("메모리 할당 실패\n");
return 1;
}
// 사용
for (int i = 0; i < n; i++) {
ptr[i] = i * 10;
}
// 출력
for (int i = 0; i < n; i++) {
printf("%d ", ptr[i]);
}
// 메모리 해제 (중요!)
free(ptr);
ptr = NULL;
return 0;
}
실전 예제: 배열의 최대값 찾기
#include <stdio.h>
int findMax(int *arr, int size) {
int max = *arr; // arr[0]
for (int i = 1; i < size; i++) {
if (*(arr + i) > max) {
max = *(arr + i);
}
}
return max;
}
int main() {
int numbers[5] = {5, 2, 8, 1, 9};
int max = findMax(numbers, 5);
printf("최대값: %d\n", max);
return 0;
}
실전 예제: 문자열 길이 구하기
#include <stdio.h>
int stringLength(char *str) {
int length = 0;
while (*str != '\0') {
length++;
str++;
}
return length;
}
int main() {
char str[] = "Hello";
printf("길이: %d\n", stringLength(str));
return 0;
}
포인터 사용 시 주의사항
- 초기화: 포인터를 사용하기 전에 반드시 초기화
- NULL 체크: 역참조 전에 NULL인지 확인
- 범위 확인: 배열 범위를 벗어나지 않도록 주의
- 메모리 해제:
malloc으로 할당한 메모리는 반드시free로 해제
다음에 공부할 내용
다음 포스트에서는 문자열 처리에 대해 공부해보겠습니다.