사용할 메모리의 범위를 기억하는 방법
자신이 사용할 메모리의 범위를 기억하는 방법은 크게 두가지가 있다.
시작주소와 끝 주소로 메모리 범위 기억하기
시작주소와 끝 주소로 메모리 범위를 기억하려면 각각의 주소를 기억하는 데 총 8바이트가 필요하다.
시작주소인 100번지를 저장하는데 4바이트가 필요하고 끝 주소인 103번지를 저장하는데 또 4바이트가 필요하기 때문이다.
시작주소와 사용할 크기로 메모리 범위 기억하기
'시작주소'와 '사용할크기'로 메모리 범위를 기억하는 것도 두가지 정보를 기억해야 합니다.
시작 주소인 100번지를 저장하는 데 4바이트가 필요하고, 사용할 크기를 저장하는데 또 4바이트가 필요합니다.
그런데 c언어 문법은 메모리를 사용할 때 항상 그 메모리의 크기를 먼저 결정하도록 되어 있다. 예를 들어 정수 값 5를 저장하고 싶다면 int data;와 같이 변수를 선언해야하는데 이 때 사용할 메모리의 크기는 int형으로 선언했기 때문에 4바이트로 결정된다. 그리고 data = 5; 명령을 사용하면 컴파일러는 data라는 변수가 4바이트라는 것을 이미 알고 있기 때문에 메모리에 4바이트 크기로 5를 대입하도록 명령을 구성하게 된다. 결국 사용할 메모리 크기는 명령문에 포함되어 있기 때문에 자신이 사용할 메모리의 시작주소만 기억하면 된다는 뜻이다.
포인터 변수의 주소 연산
포인터가 자신이 가리킬 대상 메모리의 시작 주소만 기억하면 되기 때문에 갖게 되는 특성이 있다.
short data = 0;
short *p = &data; //&는 뒤의 변수의 주소를 받는다는 뜻
p = p + 1; //포인터 변수에 저장된 주소 값을 1만큼 증가시킴
이처럼 포인터 변수에 +1을하면 자신이 가리키는 대상의 크기만큼 증가하는데 이것을 '포인터 변수의 주소 연산'이라고 한다.
char *p1 = (char *)100; // p1에 100번지를 저장함
short *p2 = (short *)100; // p2에 100번지를 저장함
int *p3 = (int *)100; // p3에 100번지를 저장함
double *p4 = (double *)100; // p4에 100번지를 저장함
p1++; //가리키는 대상의 크기가 char형(1바이트)이기 때문에 p1에 저장된 주소 값이 101이됨
p2++; //가리키는 대상의 크기가 short형(2바이트)이기 때문에 p2에 저장된 주소 값이 102가됨
p3++; //가리키는 대상의 크기가 int형(4바이트)이기 때문에 p3에 저장된 주소 값이 104가됨
p4++; //가리키는 대상의 크기가 double형(8바이트)이기 때문에 p4에 저장된 주소 값이 108이됨
포인터와 대상의 크기
int *p라고 포인터 변수를 선언할 때 int 자료형은 포인터 변수의 크기를 의미하는것이 아니라 포인터 변수가 가리키는 대상의 크기를 의미하는 것이다.
int data = 0;
int *p = &data; // 포인터 변수 p는 4바이트 크기의 메모리를 가진다.
포인터가 가리킬 수 있는 크기와 실제 대상의 크기가 다를 수도 있다.
int data = 0;
short *p = (short *)&data; //포인터 변수 p는 2바이트 크기의 메모리를 가리킬수 있는 능력을 가지고 있지만 4바이트 크기인 data 변수를 가리킬 수도 있다.
위 예제는 p가 가지고 있는 주소값을 옮기는 방식으로 작업했는데, p의 주소값을 변경하지 않고 data 변수 값을 1바이트씩 출력하고 싶다면 반복문 코드만 다음과 같이 변경하면 된다.
void *형 포인터
대상의 크기를 모른다면 사용하는것이 void키워드로 '정해져 있지 않다'는 의미를 가지고 있다.
int data = 0;
void *p = &data //data의 시작주소를 저장함
*p = 5; //오류발생 : 대상 메모리의 크기가 지정되지 않음
*주의할점 : void *는 주소를 사용할 때 반드시 '사용할 크기'를 표기해야 한다.
int data = 0;
void *p = 5;
*(int *) p = 5; //형 변환 문법을 사용하여 대상의 크기를 4바이트로 지정하므로 data변수에 5가 저장됨
void* 는 포인터의 기능을 사용할 수 없는 것이 아니라 자신이 사용할 대상의 크기 지정을 잠시 미룰 수 있다는 장점을 가지고 있다.
void *형 포인터 변수는 char *형이든 int*형이든 형 변환없이 모두 저장할 수 있다.
void *를 사용하여 대상 메모리의 크기 조절하기
이 예제는 4바이트 크기의 정수를 저장하는 data변수가 있는데 이 변수에 저장된 값을 그대로 출력하지 않는다. 사용자가 type 변수에 값 1을 지정하면 data변수의 1바이트 값만 출력하고, 2를 지정하면 data변수의 2바이트값을 출력하며, 4바이트를 지정하면 data 변수의 4바이트 값, 즉 전체값을 출력하도록 만든다.
'C언어' 카테고리의 다른 글
10-2) 표준입력함수 - scanf (0) | 2021.03.03 |
---|---|
10) 표준 입력 함수 - getchar, gets (0) | 2021.02.25 |
9)포인터 (0) | 2021.01.30 |
8) 배열 (0) | 2021.01.24 |
7) 지역 변수와 전역 변수 (0) | 2021.01.22 |