C언어로 포인터의 기본 개념 이해하기!
포인터(pointer)는 프로그래밍 언어에서 변수의 메모리 공간의 주소를 가리키는 변수를 말한다. 포인터가 가리키는 값을 가져오는 것을 역참조라고 한다.
일반적으로 포인터는 메모리 주소로 바꿀 수 있다. 포인터는 다른 변수나 함수를 가리키도록 사용된다.
const
와 같은 고정값 변수 외의 모든 변수는 메모리 중에 RAM
에 할당C언어에서 변수는 정적변수와 동적변수가 있다. 처리할 데이터의 숫자를 예측할 수 있다면 정적으로 선언하면 된다. 예시) 배열변수
그러나 데이터 처리를 미리 예측할 수 없다면 최대의 데이터 처리량을 정하고 정적으로 선언할 수 밖에 없다. 이 문제를 해결하기 위해 동적 변수를 사용한다.
C에서는 전통적으로 동적할당 변수를 잡을 경우 malloc()
함수를 사용하여 데이터 저장공간을 확보한다.
malloc()
: 힙영역으로부터 데이터 공간을 할당 받는다.realloc()
: 이미 할당된 메모리 공간의 크기를 조정한다.free()
: 더 이상 쓸 필요가 없는 메모리 공간을 힙영역에 반환한다프로세서의 힙공간은 제한적이다.
MFC(마이크로소프트 파운데이션 클래스 라이브러리(Microsoft Foundation Class Library)는 C++용 프로그램 라이브러리)와 같은 윈도 프로그램의 경우, 필요에 따라 운영 체제의 자원을 할당 받아 동적공간을 확보할 수 있다
이것 역시 동적 할당이기 때문에 포인터 변수를 사용하여 처리한다.
프로세서에서 할당 받은 공간은 실행이 끝날 때까지 동적으로 유지되지만, 이와 관련된 할당은 운영 체제와 관련 되어 있으므로 메모리 공간을 잠금을 할 경우도 있다.
이 작업이 제대로 이루어지지 않을 경우 운영체제는 리소스 부족, 알 수 없는 오류, 잘못된 연산 수행과 같은 오류를 일으킨다
int a = 5;
int *b = &a;
int *b = &a;
처럼 선언할 때에는 변수명 앞에 *를 붙혀서 포인터 변수임을 명시
선언한 이후에 *b
라고 쓰게 되면, 포인터 변수 b가 가리키는 주소의 값을 의미. 즉 5가 된다
&a
는 변수 a
에 &
를 붙힘으로 a
의 주소값을 의미
이름 | 설명 |
---|---|
주소 연산자(&) | 변수 앞에 붙어서 변수의 메모리 시작 주소 값을 구함 |
포인터(*) | 포인터 변수를 선언할 때 사용 |
간접 참조 연산자(*) | 선언된 포인터 변수가 가리키는 변수를 구함 |
#include <stdio.h>
int main(void) {
int a = 5;
int *b = &a; // (1)
printf("%d\n", *b); // (2)
system("pause");
return 0;
}
(1) 이때의 *b
의 *
은 포인터. 포인터 변수 b가 a를 가리키고 있다
(2) 이때의 *b
의 *
은 간접 참조 연산자. 포인터 변수 b가 가리키고 있는 변수 값을 가리키고 있다. 즉, 5
다중 포인터의 개념도 있다. 예시) 포인터의 포인터
int *a = 5;
int *b = &a;
int **c = &b;
#include <stdio.h>
int main(void) {
int a = 10;
int b[10]; // (1)
b = &a; // (2)
system("pause");
return 0;
}
(1) 변수 b를 선언하고 10 크기의 배열이라고 지정
(2) 변수명 b는 상수이기 때문에 다른 주소값으로 변경할 수 없다. 즉 오류 발생.
하지만 반대로 포인터를 배열처럼 사용할 수도 있다
#include <stdio.h>
int main(void) {
int a[5] = {1, 2, 3, 4, 5};
int *b = a; // (1)
printf("%d\n", b[2]); // (2)
system("pause");
return 0;
}
(1) b라는 포인터 변수를 선언하고 a를 가리키게 함
(2) b[2]를 출력. 즉 b가 가리키고 있는 a[2]를 출력하므로 결과는 3
배열의 이름은 배열의 원소의 첫 번째 주소가 된다
#include <stdio.h>
int main(void) {
int a[5] = {1, 2, 3, 4, 5};
int *b = &a[0]; // (1)
printf("%d\n", b[2]);
system("pause");
return 0;
}
(1) 배열의 첫 번째 원소 값을 넣어도 동일하기 동작.
즉 int *b = a
와 int *b = &a[0]
는 같은 의미
#include <stdio.h>
void function() {
printf("hello world");
}
int main(void) {
printf("%d\n", function); // (1)
system("pause");
return 0;
}
(1) function이라는 함수의 메모리 주소값이 출력
함수 포인터는 특정한 함수의 반환 자료형을 지정하는 방식으로 선언할 수 있다.
함수 포인터를 이용하면 형태가 같은 서로 다른 기능의 함수를 선택적으로 사용할 수 있다.
반환 자료형(*이름)(매개 변수) = 함수명; |
---|
#include <stdio.h>
void myFunction() {
printf("hello");
}
void yourFunction() {
printf("world");
}
int main(void) {
void(*fp)() = myFunction;
fp();
fp() = yourFunction;
system("pause");
return 0;
}
두 개의 함수가 차례대로 실행되면서 hello world를 출력