오늘 간단한 퀴즈 봤는데
개같이 봐가지고 관련해서 공부하려 한다
쥐뿔도 몰라도 정글 올 수 있다고 홍보하지만
진짜 쥐뿔도 모르면 주옥같은 일이 벌어질테니 어느정도 알고가자
별건 아니고 C에서의 포인터 연산자와 배열간의 관계다
알면 쉽지만 모르면 맞아야 한다 ㅇㅇ
검색하면 더 잘나올테지만 그래도 대강 설명해보겠다
*
, &
이 대표적으로 존재한다
&x
를 가정한다면 이는 x
의 위치(메모리 주소)를 의미한다 -> 참조
*p
를 가정한다면 p
의 값을 의미한다 -> 역참조
예시
int x = 10; // 값 int *p = &x; // p는 x의 주소를 담음 *p = 20; // 역참조로 x를 바꿈 -> x == 20
관련해서 void
나 **
도 있다
void
의 경우 어떤 타입이든 가리킬 수 있다
타입같은 건 신경 안쓰고 그냥 가리키는 터라 역참조는 불가능하다. C에서는 값바꾸거나 하려면 타입을 알아야 메모리 위치에 기록가능하니 말이다
**
는 이중 포인터라고 하는데 별 거 아니고 **p
라고 한다면 *p
를 가리키는 거다
실제 값이 *p
를 통해 알 수 있다면 *p
의 위치를 **p
로 알아서 *p
를 갖고 놀 수 있는거다
const
란 것도 있는데 읽기 전용으로 만드는 거다
아무튼 위의 내용은 당연한 내용이다
좀 어려운 건 포인터 산술이다
이는 배열과도 연관이 있는 상당히 중요한 내용이다
p + n
, p - n
, p++
, p--
: 타입 크기 단위로 이동
int *p; p+1
은 다음 int로 이동
여기서 왜 void
는 역참조 불가한지 알 수 있다
포인터 산술에서 이동할때 int
라는 타입을 알기에 int 타입의 바이트만큼 메모리 주소에서 이동하는데
void
의 경우 타입이 전무하기에 몇바이트 이동해야하는지 프로그램에서 알지 못한다
void
를 역참조 하고 싶을시 올바른 타입으로 캐스팅 꼭 해줘야 한다
void *vp = malloc(sizeof(int));
*(int*)vp = 7; // 캐스트 후 역참조
free(vp);
그리고 포인터 산술을 할때에는 순서가 중요하다
C 주의점에서 관련된건 확인해봐라 (사실 보지 마라 여기가 더 꼼꼼하다)
대충 이런거다
int a[]={1,2,3};
int *p = a;
printf("%d\n", *p++); // 1 출력, p는 이제 a+1
printf("%d\n", (*p)++); // 2 출력하고, 그 칸 값이 3이 됨
printf("%d\n", *++p); // p를 먼저 a+2로, 그 값 3 출력
*p++
== *(p++)
(*p)++
는 역참조한 값 증가여러 산술식을 쓸 때 괄호를 잘 씌워주라 이 말이야
배열은 사실상 포인터라고 한다
파이썬과 좀 달라서 개념이 헷갈렸다
C에서 2차원 배열은 1차원 메모리의 연속이다
예: int a[R][C];
a[0][0] a[0][1] ... a[0][C-1] | a[1][0] ... a[1][C-1] | ... | a[R-1][0] ... a[R-1][C-1]
^ a (== &a[0]) ^ a+1 (== &a[1]) ... ^ a+(R-1) (행 포인터 관점)
주소 공식(중요):
int a[R][C];
&a[i][j] == (int*)a + (i*C + j) == *(a + i) + j // 타입: int*
a[i][j] == * ((int*)a + i*C + j) == *(*(a + i) + j) // 타입: int
그리고 크기 구할때에도 차이가 있다
int a[10];
int *p = a; // int*
int (*pa)[10] = &a; // int (*)[10]
printf("%zu %zu\n", sizeof a, sizeof p); // 40(예: 4바이트 int) vs 8(포인터)
별건 아니고 배열 크기냐 포인터 크기냐다
// 선언 읽기
int *p; // p: pointer to int
int **pp; // pp: pointer to pointer to int
int (*fp)(void); // fp: pointer to function(void) returning int
int (*ap)[10]; // ap: pointer to array[10] of int
// const 위치
const int *p; // pointer to const int
int * const p2 = &x; // const pointer to int
const int * const p3 = &x; // const pointer to const int
// 산술/우선순위
*p++ // *(p++) : 현재값 사용 후 p 이동
(*p)++ // 그 칸의 값 증가
*++p // p 먼저 이동 후 역참조
*(p+1) // 다음 요소
// 배열/포인터 차이
sizeof a // 배열 크기 전체
sizeof &a // 배열 포인터 크기
sizeof p // 포인터 크기
좀 대충 다뤘기에 다음에 몇번 추가로 다루겠다
(아마도)