프로그래밍 1 1 Chapter 8. Pointers May, 2016 Dept. of software Dankook University http://embedded.dankook.ac.kr/~baeksj
포인터의개념 (1/6) 2 포인터란 : 다른객체를가리키는변수 객체의메모리주소를저장하는변수 기호적방식 (symbolic way) 으로주소사용 포인터와관련된연산자 & * int main() int num; int *pnum; int num; int *pnum; 0xfffffffc 번지 memory 7 pnum = # *pnum = 7; printf("%d\n", num); c 번지 8 번지 4 번지 p 는포인터자신, *p 는포인터가가리키는객체를의미 0 번지 32bits
포인터의개념 (2/6) 3 포인터를사용하는이유 // 매개변수예제프로그램 1 memory void swap(int, int); void swap(int x, int y) int tmp; int x; int y; 2 3 tmp = x; x = y; y = tmp; int main() int a=2, b=3; int tmp; int a; printf("a=%d, b=%d\n", a, b); swap(a,b); printf("a=%d, b=%d\n", a, b); int b; 2 3 32bits
포인터의개념 (3/6) 4 포인터를사용하는이유 // 매개변수예제프로그램 2 memory void swap(int *, int *); void swap(int *x, int *y) int tmp; tmp = *x; *x = *y; *y = tmp; int main() int a=2, b=3; int *x; int *y; int tmp; scanf() 에서 & 사용한이유를이제는.. int a; printf("a=%d, b=%d\n", a, b); swap(&a, &b); printf("a=%d, b=%d\n", a, b); int b; 2 3 포인터는함수인자, 문자열처리, 리스트, 트리, 구조체, 통신프로토콜스택, 가상함수, 해쉬등에서매우중요하게사용됨. 32bits
포인터의개념 (4/6) 5 포인터를사용시주의사항 객체를가리킨이후에사용가능 int q = 100; int *p; *p = 100; printf("%d\n", *p); printf("%d\n", q);
포인터의개념 (5/6) 6 포인터를사용시주의사항 포인터가가리키는객체의유형은포인터유형과동일해야 double q; char ch; int *p; compile 시 warning 이발생.. ch = 'A'; p = &ch; printf("%x %x\n", ch, *p); q = 1234.56; p = &q; printf("%lf, %lf\n", q, *p);
포인터의개념 (6/6) 7 포인터가가리키는공간의동적할당 / 해제 #include <stdlib.h> // 동적할당과해제를위해추가 main() int *pi; pi = malloc(4); *pi = 1234; printf("%d\n", *pi); free(pi); 반드시 free 필요.
포인터관련연산자 *, &, +, ++, -, -- 포인터식 (1/4) 포인터의각원소는포인터식으로접근 char *pch, arr_ch[] = "ABCDEFG"; int *pi, arr_int[] = 10, 20, 30, 40, 50; double *pd, arr_double[] = 1.1, 2.2, 3.3, 4.4, 5.5; 8 pch = arr_ch; pi = arr_int; pd = arr_double; 배열이름은실제로배열의시작주소이다!!. 따라서포인터에치환할때주소연산자없음 printf("%c, %c\n", *pch, arr_ch[0]); printf("%d, %d\n", *pi, arr_int[0]); printf("%lf, %lf\n\n", *pd, arr_double[0]); printf("%c, %c\n", *(pch+2), arr_ch[2]); printf("%d, %d\n", *(pi+2), arr_int[2]); printf("%lf, %lf\n\n", *(pd+2), arr_double[2]); 포인터식의모양에주의 pch = (char *)200; printf("%d\n", pch+2); pi = (int *)200; printf("%d\n", pi+2); 결국포인터수식은포인터의 pd = (double *)200; printf("%d\n", pd+2); 유형에따라다른결과를갖는다 ( 프로그래머의편의성을위해 )
포인터식 (2/4) 9 포인터식 int a[] = 10, 20, 30, 40, 50; 0xfffffffc 번지 memory int *p; p = a; 0xfffffffc 번지 memory 50 50 40 40 a[2] 30 p+2 30 a[0] a 20 10 &a[2] &a[0] p+0 p 20 10 *(p+2) *p c번지 8번지 4번지 0번지 c번지 8번지 4번지 0번지 32bits 1 차원배열에서 a 와 &a[0] 는같다. 32bits
포인터식 (3/4) 10 포인터식에익숙해지자!! int arr_int[] = 10, 20, 30, 40, 50; int *pi; pi = arr_int; 20 을포인터식으로출력하려면? printf("%d\n", *(pi+1)); 40 을포인터식으로출력하려면? printf("%d\n", *(pi+3)); printf("%d\n", *pi+3); 를하면? 포인터의강력한동시에개발자가많이장점이며실수하는부분 printf("%d\n", *(pi+5)); 를하면?
포인터식 (4/4) 11 포인터연산자의우선순위 int *pi, arr_int[] = 10, 20, 30, 40, 50; int result; pi = arr_int; result = (*pi)++; 를하면? result = *pi++; printf("%d, %d, %d\n", *pi, arr_int[0], arr_int[1]); printf("result = %d\n", result); printf("%d\n", *(pi+1)); 포인터수식은곱셈, 나눗셈은허용안됨. 실수덧셈도허용안됨
배열과포인터 (1/4) 배열은포인터와유사한성격을갖는다 색인없이배열이름을사용하면, 배열이름은그배열에대한포인터기능을수행 ( 배열의이름은포인터상수 ) 배열이름을그대로 ( 주소연산자없이 ) 포인터에치환가능 색인없는배열이름에포인터연산적용가능 포인터가배열을가리킬경우, 포인터에색인적용가능 12 int a[5] = 10, 20, 30, 40, 50; int *p; p = &a[0]; 도가능 printf("%d %d %d\n", a[0], a[2], a[4]); p = a; printf("%d %d %d\n", *p, *p+2, *p+4); printf("%d %d %d\n", *p, *(p+2), *(p+4)); printf("%d %d %d\n", *a, *(a+2), *(a+4)); printf("%d %d %d\n", p[0], p[2], p[4]);
배열과포인터 (2/4) 13 배열과포인터에서주의사항 포인터는가리키는위치를수정할수있지만, 배열은안됨 포인터명자체는메모리를차지, 배열명자체는메모리를차지하지않음 // 배열과포인터의차이점 int a[5] = 10, 20, 30, 40, 50; int *p; printf("%d\n", a[0]); printf("%d\n", a[1]); p = a; printf("%d\n", *p++); printf("%d\n", *p++); printf("%d\n", *a++); printf("%d\n", *a++); 배열의이름은포인터상수 error: lvalue required as increment operand 포인터가일반적이고강력함. 배열은직관적이라배우기쉽고오류가능성이적음
배열과포인터 (3/4) 14 2 차원배열을포인터로접근 // 2 차원배열을포인터로접근 int a[5][2] = 10, 20, 30, 40, 50, 60, 70, 80, 90, 100; int *p; p = &a[0][0]; p = a; p = a[0]; printf("%d\n", *p); printf("%d\n", *(p+1)); printf("%d\n", *p+1); *( 시작주소 + 첫번째색인 * 열의전체개수 + 두번째색인 ) printf("%d\n", *(p+2*2+1)); printf("%d\n", *(p+4*2+0)); p = a[2]; printf("%d\n", *p); printf("%d\n", *(p+1));
배열과포인터 (4/4) 15 포인터사용예 compiler에서 lexical analysis ( 어휘분석 ) 입력문장을각 token으로구분 예를들어 Pointers are fun to use 문장을입력받아 token으로구분 #include <ctype.h> // lexical analysis char input[80]; char tmp_buf[12]; char *p, *q; printf("enter any Sentences\n"); gets(input); p = input; q = tmp_buf; while (*p) 이러한프로그램방식에익숙해져야.. if (isalnum(*p)) *q++ = *p++; else *q = '\0'; printf("token = %s\n", tmp_buf); p++; q = tmp_buf; *q = '\0'; printf("token = %s\n", tmp_buf);
문자열상수포인터 16 문자열상수는컴파일러가별도테이블 ( 메모리 ) 에서관리 // 문자열상수포인터예제 char *pch; pch = "Is it correct?"; printf("%c\n", *pch); char [] pch = "Is it correct?"; 문자열상수는결국문자열을가리키는주소 printf(" 나의 C 실력은 %c\n", *"Fantastic"); printf(" 나의 C 실력은 %s\n", (char *)"Fantastic"); 이제는 printf() 에서 %c 와 %s 의차이를말할수있다!!
포인터배열 17 다른기본자료형처럼포인터도배열로만들수있음 int *i[3]; int a=1, b=2, c=3; i[0] = &a; i[1] = &b; i[2] = &c; printf("%d, %d, %d\n", *i[0], *i[1], *i[2]); 예제의변수상태를그림으로그려보세요.
다중간접참조 (1/3) 18 포인터의포인터 // 다중참조의간단한예 int i, *pi, **ppi; pi = &i; ppi = π i = 10; printf("%d, %d\n", *pi, **ppi); 결국 pi, *ppi 는 &i 값을갖는다.
다중간접참조 (2/3) 19 포인터배열과다중간접참조의예 10 명의학생에국어, 영어, 수학성적출력 // 포인터의배열예 2 이문제의경우대부분프로그램에서는 2차원배열사 용. ( 옆프로그램은강의를위해인위적으로..) int kor[10] = 70, 80, 90, 75, 85, 95, 78, 88, 98, 100; int eng[10] = 78, 93, 88, 65, 70, 80, 90, 75, 85, 95; int math[10] = 75, 85, 78, 93, 88, 98, 60, 70, 80, 90; int *course[3]; // 포인터의배열 course[0] = kor; course[1] = eng; course[2] = math; printf("%d\n", *(course[1]+2)); printf("%d\n", *(course[2]+4)); printf("%d\n", *(*(course+1)+1)); printf("%d\n", *(*(course+2)+3)); // 2 차원배열을사용하면 main() int course[3][10] = 70, 80, 90, 75, 85, 95, 78, 88, 98, 100, 78, 93, 88, 65, 70, 80, 90, 75, 85, 95, 75, 85, 78, 93, 88, 98, 60, 70, 80, 90 ; printf("%d 번의세과목성적 : %d, %d, %d\n", 0, course[0][0], course[1][0], course[2][0]); printf("%d 번의세과목성적 : %d, %d, %d\n", 7, *(*(course+0)+7), *(*(course+1)+7), *(*(course+2)+7)); printf("%d 번의세과목성적 : %d, %d, %d\n", 0, *(*(course+0)+0), *(*(course+1)+0), *(*(course+2)+0)); printf("%d 번의세과목성적 : %d, %d, %d\n", 7, *(*(course+0)+7), *(*(course+1)+7), *(*(course+2)+7));
다중간접참조 (3/3) 20 포인터배열과다중간접참조의예 문자열상수배열이포인터배열로실제많이사용됨 #include <ctype.h> #include <string.h> // 악의축찾기프로그램 char *axis_of_evil[] = "iraq", "iran", "northkorea", ""; char input[80], *p; char buf[20]; int i; printf("enter any Sentences\n"); gets(input); void next_token(char *q) while (*p) if (isalnum(*p)) *q++ = *p++; else *q = '\0'; if (*p!= '\0') p++; return; *q = '\0'; return; p = input; next_token(buf); while (strcmp(buf, "")) for (i=0; strcmp(axis_of_evil[i], ""); i++) if (!strcmp(axis_of_evil[i], buf)) printf("%s is found in \"%s\ \n", axis_of_evil[i], input); next_token(buf);
포인터매개변수 21 함수의인자로포인터를사용하는경우 호출된함수에서호출한함수의변수값을변화시키려면포인터를사용 4 페이지예제참조, scanf() 및구조체의경우 배열 // 포인터매개변수 ( 배열 ) void strcpy_new(char *p, char *q) while (*q) *p++ = *q++; *p = '\0'; char dest[40], src[40] = This is the last slide."; strcpy_new(dest, src); puts(dest);
이장의결론 22 포인터의개념을이해. 포인터식이해. 배열과포인터의공통점과차이점이해. 문자열상수포인터를이해. 다중간접참조를이해. 포인터매개변수를이해.
참고 : 포인터이해에도움이될만한예제 23 // 포인터의포인터 ( 도움이되기를.^^) void func1(int x[][3]) printf("%d\n", **x); printf("%d\n", **x+1); printf("%d\n", **(x+1)); printf("%d\n", *(*x+1)); printf("%d\n", *(*(x+1)+2)); main() int a[2][3] = 10, 20, 30, 40, 50, 60; func1(a);
참고 : 함수포인터 24 // 함수포인터 int add(int x, int y) printf("%d + %d = %d\n", x, y, x+y); main() int (*p)(int, int); p = add; p(2, 3);
참고 : 배열포인터 25 // 2 차원배열을포인터식으로접근하는방법 main() int a[5][2] = 10, 20, 30, 40, 50, 60, 70, 80, 90, 100; int *p; // 1차원배열 int *q[2]; // 포인터의배열 int (*r)[2]; // 배열의포인터 p = a; // 1. 포인터로접근 printf("%d\n", *p); printf("%d\n", *(p+1)); 컴파일시에러발생. printf("%d\n", *(p+2*2+1)); 당연!!. 배열에는새로운값을치환할수없다. printf("%d\n", **a); // 2. 배열이름에포인터식적용 printf("%d\n", *(*a+1)); printf("%d\n", *(*(a+2)+1)); q = a; // 3. 포인터의배열사용하면 printf("%d\n", **q); printf("%d\n", *(*q+1)); printf("%d\n", *(*(q+2)+1)); r = a; // // 4. 배열의포인터사용하면 printf("%d\n", **r); printf("%d\n", *(*r+1)); printf("%d\n", *(*(r+2)+1));
참고 : 이런모양도가능?? 26 // 포인터식에서교환법칙은? 배열에서는? main() int a[5] = 10, 20,; printf("a[1] = %d\n", a[1]); printf("1[a] = %d\n", 1[a]); printf("*(a+1) = %d\n", *(a+1)); printf("*(1+a) = %d\n", *(1+a));