8 장포인터 김명호
내용 포인터소개 주소연산자 & 포인터변수 역참조연산자 * void 포인터 포인터연산 함수와포인터 메모리사상함수 동적메모리할당 포인터배열 const, restrict 함수포인터 1
포인터 지금까지할당받은메모리공간은변수이름으로접근했었음 예 int a, b, c; a = b + c; // a, b, c 를위한메모리할당 // a, b, c 이름으로메모리접근 포인터는데이터를가진메모리공간을주소로접근하기위해사용 메모리는각바이트별로주소가붙여진 1 차원배열 2
교재외자료 예 int a, b = 3, c = 6; a = b + c; 변수사용 a 9 b 3 c 6 CPU 3 + 6 -> 9 b + c -> a 3
교재외자료 변수사용 예 int a, b = 3, c = 6; a = b + c; 모든변수는컴파일후할당받은주소로변환됨 a (0x0004) 9 b (0x0008) 3 c (0x000c) 6 CPU 3 + 6 -> 9 Load 0x0008 Load 0x000c add Store 0x0004 4
주소연산자 & 주소연산자 & 는변수앞에오고, 주소연산수식의값은그변수가할당받은메모리주소임 예 int i; &i // i 를위한메모리가할당됨 // i 를위해할당된메모리주소 상수나수식앞에는주소연산자 & 를사용할수없음 잘못사용한예 &3 // 상수앞에서사용 &(i + 3) // 수식앞에서사용 5
값으로주소를갖는변수 포인터변수 주소연산자 & 와함께많이사용됨 선언방법 일반변수와유사하게선언하고, 변수이름앞에 * 를붙여명시함 예 int *p; int *a, b; // int 형포인터변수 p 선언 // 포인터 a 와 int 변수 b 선언 int *x, *y; // 포인터 x 와 y 선언 6
포인터변수 포인터변수가가질수있는값의범위 특정주소 0 주어진 C 시스템에서기계주소로해석될수있는양의정수집합 7
포인터변수 사용예제 int i, *p; register int v; p = 0; p = &i; p = (int *) 1776; p = 3000; p = &(i + 99); p = &v; 8
포인터변수 사용예제 int i, *p; register int v; p = 0; // p = NULL; p = &i; p = (int *) 1776; // int 형상수를 (int *) 로캐스트 p = 3000; // 오류, 상수에사용 p = &(i + 99); // 오류, 수식에사용 p = &v; // 오류, register 변수에사용 9
포인터변수 포인터변수사용 int i = 100, *p; p = &i; p가 i의주소를가짐 p가 i를포인트함 p i 100 10
역참조연산자 * 간접지정연산자라고도함 단항연산자, 우에서좌로의결합순위 p가포인터라면, *p는 p가주소인변수의값을나타냄 p p : i 의주소 *p (= i) : 100 i 100 11
프로그램 8.1 #include <stdio.h> int main(void){ } int i = 100; int *p; p = &i; printf("i 주소 : %p\n", &i); printf(" i 값 : %d\n", i); printf(" p 값 : %p\n", p); printf("*p 값 : %d\n", *p); return 0; 예제프로그램 12
프로그램결과 i 주소 : 0x23efc4 // 시스템마다다름 i 값 : 100 p 값 : 0x23efc4 // 시스템마다다름 *p 값 : 100 13
역참조연산자 * 역참조연산자가붙은포인터는일반변수와같이배정연산자좌측에올수도있음 그포인터가포인트하고있는위치를나타냄 p i 100 *p = 200; p i 200 14
프로그램 8.2 예제프로그램 #include <stdio.h> int main(void){ int i, j = 5, *p; p = &i; i = 10; printf("(p = &i)i = %d, j = %d, *p = %d\n", i, j, *p); *p = *p * j; printf("(p = &i)i = %d, j = %d, *p = %d\n", i, j, *p); p = &j; printf("(p = &j)i = %d, j = %d, *p = %d\n", i, j, *p); return 0; } 15
프로그램결과 (p = &i)i = 10, j = 5, *p = 10 (p = &i)i = 50, j = 5, *p = 50 (p = &j)i = 50, j = 5, *p = 5 16
void 형포인터변수 void 포인터변수 형이없는포인터 int *p; float x; void *v; p = &x; v = &x; p = v; // 오류, 두형이다름 17
void 포인터변수 void 형포인터변수를사용할때에는적절한형변환필요 int *p, i, j = 20; void *v; v = &j; i = *((int *)v) + 10; // v가포인트하는곳의데이터형을 int 형으로다룸 18
포인터의포인터변수 포인터변수를포인트하는포인터 int i = 100, *p = &i, **q = &p; q는포인터의포인터변수 선언문에서 ** 로명시 q p *q : p **q : i i 100 19
프로그램 8.3 #include <stdio.h> int main(void){ 예제프로그램 int i = 100, j = 200, *p = &i, **q = &p; printf("i = %d, j = %d, *p = %d, **q = %d\n", i, j, *p, **q); } printf("&i = %p, &j = %p, p = %p, *q = %p\n", &i, &j, p, *q); printf("&p = %p, q = %p\n", &p, q); *q = &j; // p = &j printf("i = %d, j = %d, *p = %d, **q = %d\n", i, j, *p, **q); printf("&i = %p, &j = %p, p = %p, *q = %p\n", &i, &j, p, *q); printf("&p = %p, q = %p\n", &p, q); return 0; 20
프로그램결과 i = 100, j = 200, *p = 100, **q = 100 &i = 0x23efc4, &j = 0x23efc0, p = 0x23efc4, *q = 0x23efc4 &p = 0x23efbc, q = 0x23efbc i = 100, j = 200, *p = 200, **q = 200 &i = 0x23efc4, &j = 0x23efc0, p = 0x23efc0, *q = 0x23efc0 &p = 0x23efbc, q = 0x23efbc 21
포인터연산 포인터연산은 C의강력한특징중하나 p와 q가포인터변수라면 p + i, p i : p가포인트하고있는곳으로부터 i번째앞또는뒤원소 p q : p와 q 사이의원소개수 22
p, p +1, p -1 포인터연산 가정 : p 가 int 형포인터, 1000 번지를포인트 p 1 996 997 998 999 P 1000 1001 1002 1003 p + 1 1004 1005 1006 1007 } 정수값 } 정수값 } 정수값 23
p - q 포인터연산 가정 : p 와 q 가 int 형포인터 q 996 997 998 999 1000 1001 1002 1003 p 1004 1005 1006 1007 } 정수값 } 정수값 } 정수값 p q : 2 24
프로그램 8.4 #include <stdio.h> int main(void){ double x[10], *p, *q; 예제프로그램 } p = &x[2]; q = p + 5; printf("q - p = %d\n", q - p); printf("(int) q - (int) p = %d\n", (int) q - (int) p); return 0; 25
프로그램결과 q - p = 5 (int) q - (int) p = 40 26
포인터와함수 C는기본적으로 " 값에의한호출 " 메커니즘사용 " 참조에의한호출 " 의효과를얻기위해서는함수정의의매개변수목록에서포인터를사용해야함 27
값에의한호출 void change_it(int k); int main(void){ int i = 10; printf(" 함수호출이전의 i 값 : %d\n", i); change_it(i); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } void change_it(int k){ k = k * k; } 28
값에의한호출 void change_it(int k); int main(void){ int i = 10; printf(" 함수호출이전의 i 값 : %d\n", i); change_it(i); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } main() void change_it(int k){ k = k * k; } i 10 29
값에의한호출 void change_it(int k); int main(void){ int i = 10; printf(" 함수호출이전의 i 값 : %d\n", i); change_it(i); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } void change_it(int k){ k = k * k; } main() change_it() i 10 k 10 30
값에의한호출 void change_it(int k); int main(void){ int i = 10; printf(" 함수호출이전의 i 값 : %d\n", i); change_it(i); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } void change_it(int k){ k = k * k; } main() change_it() i 10 k 100 31
값에의한호출 void change_it(int k); int main(void){ int i = 10; printf(" 함수호출이전의 i 값 : %d\n", i); change_it(i); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } main() void change_it(int k){ k = k * k; } i 10 32
값에의한호출 void change_it(int k); int main(void){ int i = 10; printf(" 함수호출이전의 i 값 : %d\n", i); change_it(i); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } void change_it(int k){ k = k * k; } 33
참조에의한호출 void change_it_p(int *k); int main(void){ int i = 10; int *p = &i; printf(" 함수호출이전의 i 값 : %d\n", i); change_it_p(p); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } main() void change_it_p(int *k){ *k = *k * *k; } i p 10 34
참조에의한호출 void change_it_p(int *k); int main(void){ int i = 10; int *p = &i; printf(" 함수호출이전의 i 값 : %d\n", i); change_it_p(p); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } void change_it_p(int *k){ *k = *k * *k; } main() i p 10 k change_it_p() 35
참조에의한호출 void change_it_p(int *k); int main(void){ int i = 10; int *p = &i; printf(" 함수호출이전의 i 값 : %d\n", i); change_it_p(p); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } void change_it_p(int *k){ *k = *k * *k; } main() i *k p 100 k change_it_p() 36
참조에의한호출 void change_it_p(int *k); int main(void){ int i = 10; int *p = &i; printf(" 함수호출이전의 i 값 : %d\n", i); change_it_p(p); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } main() void change_it_p(int *k){ *k = *k * *k; } i p 100 37
참조에의한호출 void change_it_p(int *k); int main(void){ int i = 10; int *p = &i; printf(" 함수호출이전의 i 값 : %d\n", i); change_it_p(p); printf(" 함수호출이후의 i 값 : %d\n", i); return 0; } void change_it_p(int *k){ *k = *k * *k; } 38
참조에의한호출 " 참조에의한호출 " 의효과를얻는방법 1. 함수매개변수를포인터형으로선언 2. 함수몸체에서역참조포인터사용 3. 함수를호출할때주소를인자로전달 39
여러개값리턴 프로그램 8.7 int divide_p(int, int, int *, int *); int main(void){ int i, j, q, r; printf(" 피제수를입력하세요 : "); scanf("%d", &i); printf(" 제수를입력하세요 : "); scanf("%d", &j); if (divide_p(i, j, &q, &r)) printf("0 으로나눌수없습니다.\n"); else printf("%d / %d : 몫은 %d 이고나머지는 %d 입니다.\n", i, j, q, r); return 0; } 40
여러개의값리턴 프로그램 8.7 int divide_p(int dividend, int divisor, { } if (divisor == 0) return -1; *quotient = dividend / divisor; *rem = dividend % divisor; return 0; int * quotient, int * rem) 41
프로그램결과 피제수를입력하세요 : 541 제수를입력하세요 : 99 541 를 ( 을 ) 99( 으 ) 로나누면, 몫이 5 이고나머지는 46 입니다. 42
여러개의값리턴 int divide_p(int dividend, int divisor, int * quotient, int * rem) divide_p() 는호출한곳으로 3개의값을전달함 quotient : 몫 rem : 나머지 0 or -1 : 상태값 (return을통해 ) 43
scanf() scanf() 에서읽어드린값을저장할인자앞에 & 를사용 예 scanf( %d, &i); scanf() 함수에서입력을처리한결과를받기위한것임 44
포인터와배열 배열과포인터는밀접한관련이있음 배열이름은포인터이고, 그값은배열의첫번째원소의주소값임 배열과포인터에는둘다배열의원소를지정하는첨자를사용할수있음 포인터변수는다른주소들을값으로가질수있지만, 배열이름은고정된주소를갖는상수포인터임 45
배열과포인터의관계 #define N 100 int a[n], i, *p; // a : int 형포인터, a[0] 의주소 p = a; // p = &a[0]; p = a + i; // a + i : a[0] 에서 i번째떨어진원소위치 ( 주소 ) *(a + i) = 10; p[i] = 10; // p[i] == *(p + i) *(p + i) = 10; a = &i; // 오류 46
배열과포인터의관계 #define N 100 int a[n], i, *p; // &a[0] : 300 번지 a = &a[0] 300 a[0] 304 a[1] 308 a[2]...... 696 a[99] 47
배열과포인터의관계 int a[n], i, *p; // &a[0] : 300 번지 p = a + 1; // p = &a[1]; a 300 p = a + 1 304 a[0] a[1]/p[0] 308 a[2]/p[1]...... 696 a[99]/p[98] 48
포인터와배열 2차원배열도인덱스를하나제거하면포인터가됨 int b[3][5]; b[i] : int 형포인터, &b[i][0] b[i] + j : &b[i][j] b[0]+1 b[1]+3 b[2]+4 b[0] b[1] b[2] b[0][0] b[0][1] b[0][2] b[0][3] b[0][4] b[1][0] b[1][1] b[1][2] b[1][3] b[1][4] b[2][0] b[2][1] b[2][2] b[2][3] b[2][4] 49
포인터와배열 2차원배열에서인덱스를두개제거하면포인터의포인터가됨 int b[3][5]; b : int [5] 형포인터 b + i : &b[i][0] 부터 int형원소 5개포인트 b b[0][0] b[0][1] b[0][2] b[0][3] b[0][4] b + 1 b[1][0] b[1][1] b[1][2] b[1][3] b[1][4] b + 2 b[2][0] b[2][1] b[2][2] b[2][3] b[2][4] 50
포인터와배열 이차원배열원소인 b[i][j] 의다양한표기방법 #define N 100 int b[n][n]; - b[i][j] - *(b[i] + j) - *(*(b + i) + j) - (*(b + i))[j] 51
배열과함수보충 배열을매개변수로갖는함수 배열매개변수는포인터임 int grade_sum2(int gr[], int size){ int sum, i; for (sum = 0, i = 0; i < size; i++) sum += gr[i]; return sum; } gr : 포인터 52
배열과함수보충 배열을매개변수로갖는함수호출 대응인자는주소값이면됨 #define N 100 int i, a[n], sum;... sum = grade_sum2(a, N); // sum = a[0] + a[1] +... + a[99] sum = grade_sum2(&a[5], 10); // sum = a[5] + a[6] +... + a[14] sum = grade_sum2(&i, 1); // sum = i 53
문자열과포인터 문자배열과문자열포인터차이 char *p = "abcde"; char s[] = "abcde"; p s a b c d e \0 a b c d e \0 54
문자열과포인터 문자배열과문자열포인터차이 char *p = "abcde"; char s[] = "abcde"; for (i = 0; i < 5; i++) printf( %c, p[i]); for (i = 0; i < 5; i++) printf( %c, s[i]); 55
문자열과포인터 문자배열과문자열포인터차이 char *p = "abcde"; char s[] = "abcde"; p[i] = x ; p = s + 3; s = p; 56
문자열과포인터 문자배열과문자열포인터차이 #define N 20 char name[n] = ""; char *name_p; scanf("%s", name); scanf("%s", name_p); // 오류?? name_p name 57
메모리사상함수 배열표기법은컴파일후포인터수식으로변환 1차원배열 int a[5]; - 프로그램코드에서 a[i] 는컴파일후 *(&a[0]+i) 가됨 - &a[0] : a[0] 원소의주소 - &a[0] + i : a[0] 으로부터 i번째원소의주소 - *(&a[0] + i) : a[0] 으로부터 i번째원소 58
2차원배열 int b[3][5]; 메모리사상함수 - 2 차원배열은 1 차원인메모리에행우선으로저장 b[0][0] b[0][1] b[0][2] b[0][3] b[0][4] b[1][0] b[1][1] b[1][2] b[1][3] b[1][4] b[2][0] b[2][1] b[2][2] b[2][3] b[2][4] b[0][0] b[0][1] b[0][2] b[0][3] b[0][4] b[1][0] b[1][1] b[1][2] b[1][3] b[1][4] b[2][0] b[2][1] b[2][2] b[2][3] b[2][4] 59
메모리사상함수 2 차원배열 int b[3][5]; b[0][0] b[0][1] b[0][2] b[0][3] b[0][4] b[1][0] b[1][1] b[1][2] b[1][3] b[1][4] b[2][0] b[2][1] b[2][2] b[2][3] b[2][4] - b[1][4] 는 b[0][0] 로부터 5 * 1 + 4 번째원소 - b[2][3] 은 b[0][0] 로부터 5 * 2 + 3 번째원소 b[i][j] : *(&b[0][0] + 5 * i + j) 60
메모리사상함수 3 차원배열 int c[2][3][5]; - c[i][j][k] : *(&c[0][0][0] + 3*5*i + 5*j + k) 다차원배열 - 같은원리가적용됨 - 배열차원이높아질수록원소를접근하기위해추가적으로필요한 * 연산과 + 연산이많아짐 61
메모리사상함수 함수헤더에서배열매개변수의가장상위차원은명시하 지않아도됨 int grade_sum_id(int gr[][m], int id) - 메모리사상함수에서가장상위차원의크기는중요하지않기때문임 62
메모리사상함수 다차원배열을사용할때주의점 - 배열을사용하면프로그래밍은쉬워지지만추가적인 * 와 + 연산이요구됨 - 프로그램의속도가떨어질수있음 - 포인터를사용하면프로그램속도를높일수있음 63
동적메모리할당 효율적인메모리사용을위해함 메모리할당함수 : calloc(), malloc() <stdlib.h> void *calloc(size_t N, size_t el_size); void *malloc(size_t N_bytes); 두함수모두할당된메모리주소를리턴함 프로그래머는 calloc() 과 malloc() 을사용하여배열, 구조체, 공용체를위한공간을동적으로생성함 사용후에는 free() 를사용하여반납 64
동적메모리할당 프로그램 8.8 일부 #include <stdlib.h>... int *grade, N;... scanf("%d", &N);... grade = (int *)calloc(n, sizeof(int)); // 또는 grade = (int *)malloc(n * sizeof(int));... for (i = 0; i < N; i++) scanf("%d", &grade[i]);... free(grade); 65
동적메모리할당 프로그램 8.8 일부 #include <stdlib.h>... int *grade, N;... scanf("%d", &N);... grade = (int *)calloc(n, sizeof(int)); // 또는 grade = (int *)malloc(n * sizeof(int));... for (i = 0; i < N; i++) scanf("%d", &grade[i]);... free(grade); 66
프로그램 8.9 일부 동적메모리할당 int (*p)[n], *q; // p : 2 차원배열을포인트하기위해... p = (int (*)[N])calloc(N * N, sizeof(int)); q = (int *) p; for (i = 0; i < N * N; i++) q[i] = i; for (i = 0; i < N; i++){ for (j = 0; j < N; j++) printf("%3d ", p[i][j]); putchar('\n'); } free(p); 67
예제코드 동적메모리할당 int (*p)[n], *q; // p : 2차원배열을포인트하기위해... p = (int (*)[N])calloc(N * N, sizeof(int)); q = (int *) p; p p + 1 *p [0] [0] [1] [1] [2] [2]...... [N-1] [N-1] [0] [1] [2]... [N-1] [0] [1] [2]... [N-1]... p + N -1 [0] [1] [2]... [N-1] 68
프로그램결과 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 69
포인터배열 단어정렬프로그램 ( 프로그램 7.12) 에서 char words[n][m]; // N = 50, M = 14 words [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] words[0] c a t \0 words[1] d o g \0 words[2] e l e p h a n t \0 words[3] h i p p o p o t a m ( X ) \0 words[4] s e a h o r s e ( X ) \0 words[5] w h a l e \0.. words[49]... * 회색부분 : 메모리낭비 70
포인터배열 다음과같이저장하면메모리를효율적으로사용할수있음 0 1 2 3 words_p c e a t \0 d o g \0 l e p h a n t \0... h i p p o p o t a m ( X ) \0 49 char * words_p[n]; 71
포인터배열 프로그램 8.10 일부 main(void): char *words_p[n]; // char * 형배열 input_words(words_p); for (i = 0; i < num_word; i++) free(words_p[i]); input_words(char *words[]): char word[11]; input_a_word(word); words[num] = (char *)calloc(strlen(word)+1, sizeof(char)); strcpy(words[num], word); 72
포인터배열 프로그램 8.10 main() i words_p input_words() words num_word c 동적메모리할당공간 a t \0 num 2 check... d o g \0 word e l e p h a n t \0 73
비교 double x; double *p[10]; double (*q)[10]; 74
비교 double x; double *p[10]; * * * * * * * * * * double (*q)[10]; * 75
비교 double x; 1004.9 double *p[10]; * * * * * * * * 1234.0 3002.0 76
비교 double (*q)[10]; 0.1 0.8 2.2 10.1 23.6 13.1 24.6 0.0 0.0 88.1 77
비교 double (*q)[10]; 0.1 0.8 2.2 10.1 23.6 13.1 24.6 0.0 0.0 88.1 1.1 10.8 77.2 14.1 4.6 83.1 28.6 0.9 9.0 8.1 78
main() 함수의인자 main() 의인자는운영체제와의통신을위해사용됨 인자의형과기능은고정되어있음 int main(int argc, char *argv[]) argc : 명령어라인인자의개수를가짐 argv : 명령어라인을구성하는문자열들을포인트함 79
프로그램 8.11 #include <stdio.h> main() 함수의인자 int main(int argc, char *argv[]) { } int i; printf(" 총인자개수 : %d\n", argc); for (i = 0; i < argc; ++i) printf("%d 번째인자 : %s\n", i, argv[i]); return 0; 80
프로그램결과 $ echo hello main 총인자개수 : 3 0 번째인자 : echo 1 번째인자 : hello 2 번째인자 : main 81
변수의사용제한설정 const volatile restrict : C99에서추가 형한정자 기억영역클래스뒤와형앞에지정 const와 restrict 82
const const 변수는초기화될수는있지만, 그후에배정되거나, 증가, 감소, 또는수정될수없음 예 const float pi = 3.14; pi = 3.141592; // 오류 배열예 // pi 에는다른값을배정할수없음 const char months[][10] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; 83
const const 변수를포인트할때주의 const int a = 7; int *p = &a; // 오류 p는 int를포인트하는보통의포인터이기때문에, 나중에 ++*p 와같은수식을사용하여 a에저장되어있는값을변경할수있기때문 84
const const 변수를포인트해야할경우 const int a = 7; const int *p = &a; 여기서 p 자체는상수가아님 p 에다른주소를배정할수있지만, *p 에값을배정할수는없음 85
const 상수포인터 int a; int * const p = &a; p 는 int 에대한상수포인터임 p 에값을배정할수는없지만, *p 에는가능함 즉, ++*p, *p = 10 등과같은수식은가능 86
const const 변수에대한상수포인터선언 const int a = 7; const int *const p = &a; p는 const int를포인트하는상수포인터임 p와 *p 값은변경이안됨 87
C99 에서추가 restrict 포인터변수에적용되며, 현재포인트되는객체는다른포인터에의해서는포인트안됨을나타냄 컴파일러가코드최적화를할수있음 예 int block_copy(int * restrict dest, int * restrict org, int size); dest 와 org 는완전히독립된객체를포인터함 88
함수이름 : 함수포인터 함수포인터 매개변수로명시된함수 : 함수포인터 함수포인터를사용하면다양한함수에같은일을적용할때유용함 89
예 함수포인터 void qsort(void *array, size_t n_els, size_t el_size, int compare(const void *, const void *)); qsort() 는다양한형의배열을퀵정렬로정렬할수있게함 el_size 크기의원소가 n_els 개있는 array 배열을정렬함 마지막매개변수인 compare 는함수포인터임 compare 는 const void * 형매개변수를두개갖고 int 형을리턴하는함수를포인터할수있음 90
qsort() int 형을위한 compare 함수예 int compare_int(const void *p, const void *q){ if (*(int *)p > *(int *)q) return 1; else if (*(int *)p < *(int *)q) return -1; return 0; } void * 형포인터인 p와 q를통해값을비교할때먼저 (int *) 로캐스트해야함 91
qsort() int compare_int(const void *p, const void *q){ if (*(int *)p > *(int *)q) return 1; else if (*(int *)p < *(int *)q) return -1; return 0; } int main(void){ int i, int_data[10] = {1, 20, 3, 4, 5, 60, 7, 8, 9, 10}; qsort(int_data, 10, sizeof(int), compare_int); for (i = 0; i < 10; i++) printf("%d ", int_data[i]); printf("\n"); } return 0; 92
qsort() qsort() 사용예 int compare_word(const void *p, const void *q){ return strcmp(*(char **)p, *(char **)q); }... qsort(words_p, num_word, sizeof(char *), compare_word); compare_word 뒤에괄호가없으므로함수포인터임 93
qsort() 프로그램 8.12 ( 일부 ) int compare_word(const void *p, const void *q){ } return strcmp(*(char **)p, *(char **)q); int main(void){ int i; char *words_p[n] = {NULL}; int i, num_word = 0; num_word = input_words(words_p); qsort(words_p, num_word, sizeof(char *), compare_word); print_words(words_p, num_word);... return 0; } 94
교재외자료 함수포인터예제 #include <stdio.h> void func_1(void){ printf("i am func_1.\n"); } void func_2(void){ printf("i am func_2.\n"); } int main(void){ void (* func)(void); func = func_1; func(); } func = func_2; func(); return 0; 95
교재외자료 함수포인터예제 I am func_1. I am func_2. 96