System Software Experiment 1Lecture 4 - Pointer
spring 2019Hwansoo Han ([email protected])
Advanced Research on Compilers and Systems, ARCS LAB
Sungkyunkwan University
http://arcs.skku.edu/
1
PC 내부 구조
2
Mainboard
CPURAM
(Memory)
Device(HDD, SSD)
Memory 구조
3
1 byte
1 byte
1 byte
RAM
주소0x0
0x1
0x2
…
Memory 구조• 변수의 크기에 따라 차지하는 메모리 공간이 다름
• char 형 변수 : sizeof (char) (1 byte)
• int 형 변수 : sizeof (int) ( 보통 4 bytes)
4
1 byte
1 byte
1 byte
RAM
int main(){ int i = 4; char c = 65;}
주소0x0
0x1
0x2
…
Memory 구조• 변수의 크기에 따라 차지하는 메모리 공간이 다름
• char 형 변수 : sizeof (char) (1 byte)
• int 형 변수 : sizeof (int) ( 보통 4 bytes)
5
RAM
int main(){ int i = 4; char c = 65;}
65
4
주소0x0
0x1
0x2
…
주소 연산자 &
• &: 변수의 주소를 계산
6
RAM
주소
int main(){ int i = 4; printf(“i: %d\n”, i); printf(“addr: %p\n”, &i);}
4
$ ./test_addri: 4addr: 1
0x0
0x1
0x2
…
Pointer
• 주소를 저장하는 변수• pointer 형 변수 : sizeof ( 포인터 타입 )
( 보통 4, 8 bytes) ex) sizeof (int *)
7
int main(){ int i = 4; int *p = &i;}
RAM
0x0
0x1
0x2
…
Pointer
• 주소를 저장하는 변수• pointer 형 변수 : sizeof ( 포인터 타입 )
( 보통 4, 8 bytes) ex) sizeof (int *)
8
0x0
4
RAM
int main(){ int i = 4; int *p = &i;}
0x0
0x1
0x2
…
참조 연산자 *
• 포인터가 가리키는 주소 안의 값을 반환
9
0x0
4
RAM
int main(){ int i = 4; int *p = &i;
printf(“*p: %d\n”, *p);
}
*p: 4
0x0
0x1
0x2
…
참조 연산자 *
• 포인터가 가리키는 주소 안의 값을 반환
10
0x0
10
RAM
int main(){ int i = 4; int *p = &i;
printf(“*p: %d\n”, *p); *p = 10; printf(“*p: %d\n”, *p); printf(“i: %d\n”, i);}
*p: 4*p: 10i: 10 0x0
0x1
0x2
…
Pointer 연산• 포인터 변수에 대한 덧셈 , 뺄셈 등의 연산이 가능• 포인터 변수의 자료형 크기만큼 연산을 수행
11
포인터 타입 +1 연산 증가 값char sizeof (char)
int sizeof (int)
unsigned long
sizeof (unsigned long)
int main(){ int *p = (int *)1000;
printf(“%d\n”, p); p++; printf(“%d\n”, p);}
10001004
Pointer 연산• 포인터 변수에 대한 덧셈 , 뺄셈 등의 연산이 가능• 포인터 변수의 자료형 크기만큼 연산을 수행
12
수식 ++ 연산의 의미*p++; p( 주소 ) 를 ++
(*p)++; p 가 가리키는 값을 ++
p++; p( 주소 ) 를 ++
Pointer 와 함수• Call-by-value
• 값에 의한 호출• Call-by-reference
• 참조에 의한 호출
13
Call-by-value
• 함수의 인자로 값을 전달
14
int sum(int a){ …}
int main(){ int i = 4;
sum(i);}
Call-by-reference
• 함수의 인자로 포인터를 전달
15
int sum(int *p){ …}
int main(){ int i = 4;
sum(&i);}
Swap Example (call-by-value)
• 변수 2 개의 값을 바꾸는 작업을 함수로 작성
16
int main(){ int a = 10, b = 20;
printf(“%d %d\n”, a, b); swap(a, b); printf(“%d %d\n”, a, b);}
void swap(int a, int b){ int temp;
temp = a; a = b; b = temp;}
10 2010 20
Swap Example (call-by-reference)
• 변수 2 개의 값을 바꾸는 작업을 함수로 작성
17
int main(){ int a = 10, b = 20;
printf(“%d %d\n”, a, b); swap(&a, &b); printf(“%d %d\n”, a, b);}
void swap(int *a, int *b){ int temp;
temp = *a; *a = *b; *b = temp;}
10 2020 10
Double Pointer
• 포인터 변수를 가리키는 포인터
18
int main(){ int a = 3; int *p = &a; int **pp = &p;
printf(“%d\n”, *p); printf(“%p\n”, pp); printf(“%p\n”, *pp); printf(“%d\n”, **pp);}
310 ( 가정 )20 ( 가정 )3
Memory 동적할당• Memory 할당 방식
• 정적인 방식 : 임의의 변수를 선언하여 사용하고 스코프를 벗어날 때 자동 해제• 변수를 선언하는 동시에 바로 할당
• 동적인 방식 : 필요한 만큼 메모리를 할당받아 사용하고 원할 때 해제 가능• malloc() 을 통해 직접 할당• free() 을 통해 직접 해제
19
Memory 동적할당
20
int main(){ char* a;}
!@#$
RAM
a →
0x0
0x1
0x2
…
0x48
0x49
0x4a
Memory 동적할당
21
int main(){ char* a = (char*)malloc(sizeof (char) * 4); 1 byte
}
0x48
RAM
0x0
0x1
0x2
…
a →
0x48
0x49
0x4a
Memory 동적할당
22
6
5
4
0x48
RAM
int main(){ char* a = (char*)malloc(sizeof (char) * 4);
printf(“%p\n”, a); *a = 4; // a: 0x48 *(a+1) = 5; // (a+1): 0x49 *(a+2) = 6; // (a+2): 0x4a printf(“%p\n”, a+1); free(a);}
4849 a →
0x0
0x1
0x2
…
0x48
0x49
0x4a
Memory 동적할당
23
0x48
RAM
int main(){ char* a; a = (char*)malloc(sizeof (char) * 4); //0x48}
a →
0x0
0x1
0x2
…
0x48
0x49
0x4a
0x4b
0x4c
0x4d
Memory 동적할당
24
0x4d
RAM
int main(){ char* a; a = (char*)malloc(sizeof (char) * 4); //0x48 … a = (char*)malloc(sizeof (char) * 2); //0x4d}
a →
0x0
0x1
0x2
…
0x48
0x49
0x4a
0x4b
0x4c
0x4d
Memory 동적할당
25
0x4d
RAM
int main(){ char* a; a = (char*)malloc(sizeof (char) * 4); //0x48 … a = (char*)malloc(sizeof (char) * 2); //0x4d free(a);}
a →
0x0
0x1
0x2
…
0x48
0x49
0x4a
0x4b
0x4c
0x4d
MemoryLeak
Memory 동적할당• Background : 변수의 스코프
26
void print_grade(){ char grade = ‘A’; printf(“%c\n”, grade); // Valid}
int main(){ print_grade(); printf(“%c\n”, grade); // ERROR
return 0;}
int main(){ if ( 1 ) { int score = 100; printf(“%d”, score); // Valid }
printf(“%d”, score); // ERROR
return 0;}
Memory 동적할당• 함수 내부에서 할당된 변수를 함수 외부에서 사용 ( 정적할당 )
27
int main(){ char* my_grade; my_grade = get_grade(); printf(“%c\n”, *my_grade);
return 0;}
char* get_grade(){ char grade = ‘A’;
return &grade; // NOT VALID}
Memory 동적할당• 함수 내부에서 할당된 변수를 함수 외부에서 사용 ( 동적할당 )
28
int main(){ char* my_grade; my_grade = get_grade(); printf(“%c\n”, *my_grade); free(grade);
return 0;}
char* get_grade(){ char* grade = (char*)malloc(sizeof (char)); *grade = ‘A’; return &grade; // Valid}
Function Pointer
• 함수의 주소를 저장하는 변수• 함수 선언
• ex) int func(int a, char b);
• 함수 포인터 선언• 함수이름 → (* 포인터이름 ) ex) int (* func_p)(int a, char b);
int (* func_p)(int, char);
• 함수 포인터 사용• ex) func_p = &func;
(*func_p)(1, ‘A’);
29
Function Pointer
• 함수의 주소를 저장하는 변수• 함수 선언
• ex) int func(int a, char b);
• 함수 포인터 선언• 함수이름 → (* 포인터이름 ) ex) int (* func_p)(int a, char b);
int (* func_p)(int, char);
• 함수 포인터 사용• ex) func_p = func;
func_p(1, ‘A’);
30
int func(int a){ return a * 2;}
int main(){ int (* func_p)(int); func_p = func; printf(“%d\n”, func_p(6) );}
12
Function Pointer
• 함수의 주소를 저장하는 변수• 함수 선언
• ex) int func(int a, char b);
• 함수 포인터 선언• 함수이름 → (* 포인터이름 ) ex) int (* func_p)(int a, char b);
int (* func_p)(int, char);
• 함수 포인터 사용• ex) func_p = func;
func_p(1, ‘A’);
31
int mul2(int input) { return input * 2; }int div2(int input) { return input / 2; }
int calc(int (* func_p)(int), int a){ return func_p(a);}
int main(){ printf(“%d\n”, calc(mul2, 6) ); printf(“%d\n”, calc(div2, 6) );}
123
Exercise 1
• 오른쪽 그림과 같은 메모리 구조가 주어졌을 때 , 포인터 연산을 이용하여 다음의 두 가지 방식으로 swap 하는 함수 내용을 작성• 직접적으로 값 (int) 을 swap• 간접적으로 값을 가리키는 포인터 (int*) 를
swap
32
0 10
20
30
40
0 1 2 3 4
0x1
0x2
0x3
0x4
0x5
0 1 2 3 4
int
int*
0x6
int** var_pp
0x1
0x2
0x3
0x4
0x5
0x6
Initial state
Exercise 1
• 오른쪽 그림과 같은 메모리 구조가 주어졌을 때 , 포인터 연산을 이용하여 다음의 두 가지 방식으로 swap 하는 함수 내용을 작성• 직접적으로 값 (int) 을 swap• 간접적으로 값을 가리키는 포인터 (int*) 를
swap
33
0 10
20
30
40
0 1 2 3 4
0x2
0x1
0x3
0x4
0x5
0 1 2 3 4
int
int*
0x6
int** var_pp
0x1
0x2
0x3
0x4
0x5
0x6
Swap Pointer
Exercise 1
• 오른쪽 그림과 같은 메모리 구조가 주어졌을 때 , 포인터 연산을 이용하여 다음의 두 가지 방식으로 swap 하는 함수 내용을 작성• 직접적으로 값 (int) 을 swap• 간접적으로 값을 가리키는 포인터 (int*) 를
swap
34
10
0 20
30
40
0 1 2 3 4
0x2
0x1
0x3
0x4
0x5
0 1 2 3 4
int
int*
0x6
int** var_pp
0x1
0x2
0x3
0x4
0x5
0x6
Swap Value
Exercise 1
• 오른쪽 그림과 같은 메모리 구조가 주어졌을 때 , 포인터 연산을 이용하여 다음의 두 가지 방식으로 swap 하는 함수 내용을 작성• gcc main.c exercise1.c• main.c 는 수정 X
35
Exercise 2
• 재귀함수를 함수포인터를 이용해 구현• 조건에 따라 다음에 실행되는 함수 (func_next)를 변경
36
Exercise 2
• 재귀함수를 함수포인터를 이용해 구현• gcc main.c exercise2.c• main.c 는 수정 X• exercise2.c 파일의 int fact(int input) 함수 안 가운데 빈칸에 적절한 코드 추가
37