용어 정리
변수: 변하는 값을 저장하는 곳. 데이터를 저장하기 위해 메모리에서 공간을 할당 받음.
주소값: 변수에서 메모리에서 할당받은 공간의 시작 주소
포인터: 위의 주소값을 저장하는 변수(또는 상수)
상수 포인터: 다른 주소값을 가리키도록 바꿀 순 있으나, 그 주소에 있는 값을 바꿀 순 없음.
포인터 상수: 다른 주소값을 가리키도록 바꿀 수 없으나, 그 주소에 있는 값을 바꿀 순 있음.
포인터 선언
변수타입* 변수명;
변수타입 * 변수명;
변수타입 *변수명 = 주소값;
으로 선언할 수 있습니다. (*이 어디 붙어도 상관없습니다.)
int a = 10
int* b = &a;
연산자
& 연산자(주소 연산자)
&변수
이렇게 사용할 수 있다.
int a = 10;
print("%p", &a); // %p 는 주소값을 출력할 때 사용합니다.
이런 식으로 & 연산자를 사용하게 되면 변수 a의 주소값이 출력됩니다.
* 연산자(참조 또는 역참조 연산자)
* 연산자는 뒤에 오는 주소값에서 그 주소에 담겨있는 값에 접근하는 데 사용합니다.
*변수
예를 들어 "*&변수"를 하게 되면 변수의 주소값에서 그 주소에 담겨있는 값을 가져오게 되므로 변수의 값이 나오게 됩니다.
int a = 948;
int* b = &a;
printf("%p %d\n", &a, *&a);
printf("%p %d", b, *b);
결과는
(a의 주소값) 948
(a의 주소값) 948
이 나오게 됩니다.
포인터 연산
포인터의 덧셈과 뺄셈
포인터의 덧셈
int a = 50;
int *b = &a;
char c = 'c';
char* d = &c;
printf("%p\n", b); //0061FF14
printf("%p\n", d); //0061FF13
printf("%p\n", b + 1); //0061FF18
printf("%p", d + 1); //0061FF14
* 포인터 간의 덧셈은 안됩니다. (쓸 이유가 없음)
* 포인터에 x만큼 더하면 주소값은 (x * 자료형) 만큼 늘어납니다.
포인터의 뺄셈
int a[2] = {50, 100};
int *a1 = a;
int *a2 = a + 1;
printf("%d\n", *a);
printf("%d\n", *(a + 1));
printf("%p %d\n", a1, *a1);
printf("%p %d\n", a2, *a2);
printf("%d\n", a2 - a1);
* 배열 자체는 배열의 첫 번째 주소를 나타내므로 *a는 배열의 첫 번째 항목, *(a+1)은 배열의 두 번째 항목이 됩니다.
* a1은 배열의 첫 번째 항목의 주소, a2는 배열의 두 번째 항목의 주소이므로 a2-a1은 배열의 두 번째 항목과 첫번째 항목의 주소의 차가 됩니다.
* a2 - a도 똑같이 첫번째 항목과 두번째 항목의 주소의 차가 되고 이걸 이용하면 a2가 배열에서 위치한 위치를 알 수 있습니다.
* lowerbound나 upperbound를 사용할 때 반환값에서 배열을 빼면 검색한 항목의 위치(index)를 알 수 있습니다.
포인터의 곱셈과 나눗셈
불가능합니다.
Call By Value
#include <stdio.h>
void test(int a){
a = 10;
printf("in test function, variable a value: %d\n", a); //10
}
int main()
{
int a = 90;
printf("before invoke test function, variable a value : %d\n", a); //90
test(a);
printf("in main function, variable a value: %d", a); //90
return 0;
}
함수의 인자에 변수의 값을 복사해서 전달해준다.
함수 내에서 값을 바꿔도 원래 변수의 값이 변하지는 않는다.
Call By Reference
#include <stdio.h>
void test(int *a)
{
*a = 10;
printf("in test function, variable a value: %d\n", *a); //10
}
int main()
{
int a = 90;
printf("before invoke test function, variable a value : %d\n", a); //90
test(&a);
printf("in main function, variable a value: %d", a); //10
return 0;
}
함수의 인자에 변수의 주소값을 전달해준다.
함수에서 참조 연산자를 이용해서 값을 바꾸면 원래 변수의 값도 변한다.
다중 포인터
포인터도 변수이므로 포인터에 대한 주소값을 저장하는 포인터를 만들 수 있습니다.
이것을 다중 포인터라 부르게 됩니다. 아래 예시를 보면
int a = 10;
int *b = &a;
int **c = &b;
printf("%p %p %p\n", &a, b, *c);
printf("%d %d %d", a, *b, **c);
포인터 c는 포인터 b의 주소값을 저장하는 2중 포인터인 것을 알 수 있습니다.
포인터를 선언할 때 변수타입* 변수명; 으로 한다고 했었는데 int **c = &b;에서 (int*)가 자료형이 됩니다.
자료형*변수명 = 주소값;
int * *c = &b;
3중 포인터 예시를 보면
int a = 10;
int *b = &a;
int **c = &b;
int ***d = &c;
printf("%p %p %p %p\n", &a, b, *c, **d);
printf("%d %d %d %d", a, *b, **c, ***d);
이런 식으로 한 겹이 추가될 때마다 자료형에 *이 하나씩 늘어나게 됩니다.
'해킹 > 과제' 카테고리의 다른 글
2. UART 찾기, 칩 구분 (0) | 2021.04.20 |
---|---|
1. 부트로더, 커널, 파일시스템 (0) | 2021.04.20 |
6. 추측 실행(Speculation Execution), 분기 예측(Branch Prediction) (0) | 2021.04.17 |
5. 비순차적 실행(Out-of-order Execution) (0) | 2021.04.17 |
4. 파이프라이닝(Pipelining) (0) | 2021.04.17 |