#include<stdio.h>
int main(void)
{
int num = 7;
int* pnum;
pnum = #
........
}
포인터 변수란? 메모리의 주소 값을 저장하기 위한 변수이다.
그러면 여기서 포인터 변수는 *pnum 일까, pnum일까? 바로 pnum이다.
위 코드를 보면 num의 주소 값을 포인터 변수인 pnum에 저장하고 있는 것을 볼 수 있다.
이러면, num의 시작 번지 주소 값이 포인터 변수 pnum에 저장이 되고,
이를 포인터 변수 pnum이 int형 변수 num을 가리킨다.라고 할 수 있다.
그렇다면 *pnum은 무엇일까? 우선,* 연산자는 포인터가 가리키는 메모리 공간에 접근할 때, 사용하는 연산자이다.
그러므로, *pnum은 포인터 변수 pnum이 가리키는 메모리 공간인 변수 num에 접근을 해서..라고 생각할 수 있다.
만약 위 코드에서 *pnum = 20; 과 같은 문장이 있었다면, 이는 포인터 변수 pnum이 가리키는 메모리 공간인 변수 num에 정수 20을 저장한다. 라는 것을 알 수 있다.
즉, 위 코드에서 포인터 변수는 *pnum이 아니라, pnum이고 *pnum은 포인터 변수 pnum이 가리키는 메모리 공간에 접근..이라는 뜻을 가지고 있다. 위 코드 블록에서 *pnum의 값은 7이다.
배열의 이름은 포인터이다. 단, 그 값을 바꿀 수 없는 '상수 형태의 포인터이다.
(% p는 주소 값의 출력에 사용되는 서식 문자이다.)
#include<stdio.h>
int main(void){
int arr[3] = { 0,1,2 };
printf("배열의 이름: %p\n", arr);
printf("첫 번쨰 요소: %p\n", &arr[0]);
printf("두 번쨰 요소: %p\n", &arr[1]);
printf("세 번쨰 요소: %p\n", &arr[2]);
return 0;
}
실행결과, 배열의 이름의 주소 값과 배열 첫 번째 요소의 주소 값이 같은 것을 알 수 있다.
cf) arr = &arr [i]의 문장이 가능할까? 불가능하다.
&연산자의 피연산자는 변수여야 하며, 상수는 피연산자가 될 수 없다. 즉 배열의 이름은 대입 연산자의 피연산자가 될 수 없다. 그러므로 결론은 배열의 이름은 배열의 시작 주소 값을 의미하며, 그 형태는 값의 저장이 불가능한 상태이다.
배열의 이름은 '상수 형태의 포인터'이고 '포인터 상수'라고 부르기도 한다.
배열의 이름을 대상으로 하는 * 연산
#include<stdio.h>
int main(void){
int arr1[3] = { 1,2,3 };
double arr2[3] = { 1.1,2.2,3.3 };
printf("%d %g\n", *arr1, *arr2);
*arr1 += 100;
*arr2 += 120.5;
printf("%d %g\n", arr1[0], arr2[0]);
return 0;
}
printf("% d % g\n", *arr1, *arr2); : arr1과 arr2가 가리키는 대상을 출력하고 있는 문장이다.
arr1은 int형 포인터이므로 4바이트 크기의 메모리를 정수의 형태로 참조하고,
arr2은 double형 포인터이므로 8바이트 크기의 메모리를 실수의 형태로 참조하게 된다.
따라서, arr1과 arr2가 가리키는 첫 번째 요소가 출력이 된다.
arr1 [3] = {2,1,3}으로 바꾸면, *arr1 = 2가 된다. arr1의 배열의 첫 번째 요소가 2로 바뀌었기 때문.
포인터 연산
#include<stdio.h>
int main(void){
int arr1[3] = { 11,22,33 };
int* ptr = arr1; //int *ptr = &arr[0];과 같은 문장.
printf("%d %d %d\n", *ptr, *(ptr + 1), *(ptr + 2));
printf("%d", *ptr); ptr++;
printf(" %d", *ptr); ptr++;
printf(" %d", *ptr); ptr--;
printf(" %d", *ptr); ptr--;
printf(" %d", *ptr); printf("\n");
return 0;
}
*(ptr + 1) : 포인터 변수 ptr은 int형 포인터 값을 1 증가시키는 연산을 할 때마다 실제로는 4가 증가한다.
포인터를 대상으로 하는 증가 연산의 결과
int형 포인터를 대상으로 n 증가 >>>>n x sizeof(int)의 크기만큼 증가. 즉, 1을 증가시키는 연산을 하면 4 증가.
<참고>
우리가 선언한 배열이 int형 배열이고 각 요소 별로 할당되는 메모리 공간의 크기는 4바이트이다. 따라서 배열 요소 간 주소 값의 차이는 4 바이트이다.
*(ptr + 1)과 *(++ptr)의 차이는 무엇 일까?
*(ptr + 1)는 +로 인해서 ptr에 저장된 값이 증가하지 않는다. 단, 증가된 값을 연산의 결과로 얻어서 * 연산을 진행하는 것뿐. 즉, 현재 배열 요소의 값(0x0012 ff50)에서 다음 배열 요소의 주소 값을 나타낼 때 ptr = 0x0012 ff54가 아닌,
ptr +1 = 0x0012 ff54로 나타낸 다는 것이다. ptr에 저장된 값은 변경되지 않는다!
*(++ptr)는 ++연산의 결과로 포인터 변수 ptr에 저장된 값이 4만큼 증가한다. 즉, 현재 배열 요소의 주소 값에서 다음 배열 요소의 주소 값을 나타낼 때, ptr = 0x0012 ff54로 나타내어진다. ptr에 저장된 값 자체를 변경한 것 이기 때문이다.
포인터는 변수 형태의 포인터 상수 형태의 포인터를 어우르는 표현인데,
그러면 포인터 그 자체의 뜻은 뭘까? 포인터는 (주소 값을) 가리키는 주체라고 생각한다.