민규최를 위한 포인터 글
변수(variable)란 무엇인가?
수학에서 변수는 변할 수 있는 수, 즉 상수(constant)와 반대 개념으로 사용이 된다.
프로그래밍에서도 변수의 성질은 마찬가지이지만,
변수는 데이터를 저장할 수 있는 메모리 공간에 붙인 이름(혹은 그냥 메모리 공간 자체)을 의미한다.
(메모리 공간에 이름을 적어 놓았기에 그 메모리 공간의 위치를 찾을 수 있어 해당 공간안에 있는 데이터 값을 바꿀 수 있다. 라고 생각하면 편함)
int a; 라는 코드를 실행하면, 아래 그림과 같이 메모리 공간이 할당되고(아래 그림에서 네모), 그 공간의 이름을 a라고 명명한다.
만약 여기서 a = 10; 이라는 코드를 실행하면, 아래 그림과 같이 a라는 메모리 공간 안에 10 이라는 데이터 값을 넣게 된다.
그런데 왜 포인터 얘기는 안 하고, 뜬금없이 변수 얘기를 하는 것인가?
포인터가 바로 변수의 일종이기 때문이다.
포인터는 메모리의 주소 값을 저장하기 위한 "변수"이다.
[포인터 선언 및 참조( *, & 연산자)]
1 2 3 4 5 6 7 8 9 10 | int main() { void *a; //void형 포인터 (차후 설명) char *b; //char형 변수/상수의 주소 값을 가질 수 있는 포인터 b int *c; //int형 변수/상수의 주소 값을 가질 수 있는 포인터 c double *d; //double형 변수/상수의 주소 값을 가질 수 있는 포인터 d return 0; } | cs |
꼴 : "포인터타입 변수명"
포인터 타입은 "자료형 + *" 으로 구성되며 연산자 *를 사용한다.
자료형(data type) | 크기 | |
정수형 | char | 1byte |
short | 2byte | |
int | 4byte | |
long | 4byte | |
실수형 | float | 4byte |
double | 8byte | |
long double | 8byte |
포인터 타입(pointer type) | 크기 | |
정수형 | char * | 4byte 혹은 8byte |
short * | 4byte 혹은 8byte | |
int * | 4byte 혹은 8byte | |
long * | 4byte 혹은 8byte | |
실수형 | float * | 4byte 혹은 8byte |
double * | 4byte 혹은 8byte | |
long double * | 4byte 혹은 8byte |
참고) int* a, int *a, int * a 모두 다 같다. 하지만 명심하자, (포인터)변수 명은 *a가 아닌, a이다!
& 연산자는 주소 값을 알아내기 위해 사용된다.
1 2 3 4 5 6 7 | int main() { int a = 10; int *pointerA = &a; return 0; } | cs |
위 code를 실행하면 순서가 다음과 같이 된다.
1. int a = 10;
메모리상에 int형 공간을 할당하고 이름을 a라고 한다.
(이 때 프로그램이 잡은 메모리 공간의 주소는 0x1000이라 하자.)
그리고 a라는 공간에 10이라는 값을 넣는다.
2. int *pointerA = &a;
메모리상에 int형 포인터 공간을 할당하고 이름을 pointerA라고 한다.
(주의!!! *pointerA가 이름이 아니다!!! *pointerA는 다른 의미. 아래에서 설명)
(이 때 프로그램이 잡은 메모리 공간의 주소는 0x2000이라 하자.)
&a는 a라는 공간의 실제 메모리 상의 주소(즉, 0x1000)을 알려준다.
&연산자는 주소 값을 구할 때 사용하는 연산자이다.
우리가 a = 10 이라고 하는 것 처럼,
pointerA = 0x1000 값을 assign한다.
하나의 그림으로 다시 그려보면, 아래와 같다
pointerA라는 (포인터)변수는 변수 a를 가리킬 수 있다.(==변수 a에 접근할 수 있다) 왜? a라는 공간의 주소를 알고 있으니까!
즉 pointerA를 통해 a라는 공간에 무슨 값이 있는지 알아낼 수 있다.
우리가 포인터를 선언할 때
"자료형type *변수명" 으로 선언할 때 사용했던 * 연산자가 포인터가 가리키는 메모리 값을 참조 할 때도 사용이 된다.
1 2 3 4 5 6 7 8 9 10 | int main() { int a = 10; int *pointerA = &a; printf("%d\n", pointerA); printf("%d\n", *pointerA); return 0; } | cs |
6번 째 줄은, (포인터)변수 pointerA라는 메모리 공간에 있는 값을 출력한다.
즉, 0x1000이 출력이 된다(a라는 메모리 공간의 주소)
7번 째 줄은 (포인터)변수 pointerA가 가리키는 공간에 있는 값을 출력한다.
현재 메모리 0x1000에 있는 값을 출력한다는 말이다.
즉, 10의 값이 출력된다.
[포인터 타입]
포인터 타입(pointer type) | 크기 | |
정수형 | char * | 4byte 혹은 8byte |
short * | 4byte 혹은 8byte | |
int * | 4byte 혹은 8byte | |
long * | 4byte 혹은 8byte | |
실수형 | float * | 4byte 혹은 8byte |
double * | 4byte 혹은 8byte | |
long double * | 4byte 혹은 8byte |
모든 포인터 타입은 4byte 혹은 8byte로 크기가 동일한데, 왜 여러개의 타입이 존재하는 것일까?
포인터 타입이 크기가 동일한 이유는, 포인터 변수는 메모리공간의 주소를 담기 때문이다.
만약, char 변수를 선언을 하든, double 변수를 선언을 하든, 두 변수가 할당 받는 메모리의 주소는 4byte 혹은 8byte 로
동일할 것이기 때문이다.
하지만 char는 1byte 공간이 할당되고, double은 8byte 공간이 할당되므로
포인터를 이용하여 메모리를 참조할 때, 몇 바이트를 읽을지 결정을 해주어야 한다. 그래서 다양한 타입이 존재한다.
1 2 3 4 5 6 7 8 9 10 | int main() { unsigned char a = 0xff; unsigned char *pointerA = &a; unsigned int b = 0xffffffff; unsigned int *pointerB = &b; return 0; } | cs |
위 코드를 그림을 그려보면 다음과 같이 된다.
'Programming > C' 카테고리의 다른 글
C언어 포인터와 배열(C언어 pointer and array) (0) | 2020.10.19 |
---|---|
C언어 포인터 활용(C언어 use of pointer) feat. swap함수 (0) | 2020.10.17 |
가변길이 구조체(flexible array member) (0) | 2020.10.15 |
const와 pointer (0) | 2019.07.25 |
Visual studio 디버깅 하는법 (0) | 2017.01.18 |