쉽게풀어쓴 C 언어 Express 제 11 장포인터 컴퓨터프로그래밍기초
이번장에서학습할내용 포인터이란? 변수의주소 포인터의선언 간접참조연산자 포인터연산 포인터와배열 포인터와함수 이번장에서는포인터의기초적인지식을학습한다. 컴퓨터프로그래밍기초 2
포인터란? 포인터 (pointer): 주소를가지고있는변수 컴퓨터프로그래밍기초 3
메모리의구조 변수는메모리에저장된다. 메모리는바이트단위로액세스된다. 첫번째바이트의주소는 0, 두번째바이트는 1, 컴퓨터프로그래밍기초 4
변수와메모리 변수의크기에따라서차지하는메모리공간이달라진다. char 형변수 : 1 바이트, int 형변수 : 4 바이트, int i = 10; char c = 69; float f = 12.3; 컴퓨터프로그래밍기초 5
변수의주소 변수의주소를계산하는연산자 : & 변수 i 의주소 : &i 컴퓨터프로그래밍기초 6
변수의주소 int i= 10; char c = 69; float f = 12.3; printf("i의주소 : %u\n", &i); // 변수 i의주소출력 printf("c의주소 : %u\n", &c); // 변수 c의주소출력 printf("f 의주소 : %u\n", &f); // 변수 f 의주소출력 return 0; i의주소 : 1245024 c의주소 : 1245015 f의주소 : 1245000 컴퓨터프로그래밍기초 7
포인터의선언 포인터 : 변수의주소를가지고있는변수 int i = 10; int *p = &i; // 정수형변수 i 선언 // 변수 i 의주소가포인터 p 로대입 컴퓨터프로그래밍기초 8
다양한포인터의선언 char c = 'A'; float f = 36.5; double d = 3.141592; // 문자형변수 c // 실수형변수 f // 실수형변수 d char *pc = &c; float *pf = &f; double *pd = &d; // 문자를가리키는포인터 pc // 실수를가리키는포인터 pf // 실수를가리키는포인터 pd 컴퓨터프로그래밍기초 9
간접참조연산자 간접참조연산자 *: 포인터가가리키는값을가져오는연산자 int i= 10; int *p = &i; printf("%d\n", *p); // 10 이출력된다. *p = 20; printf("%d\n", *p); // 20이출력된다. 컴퓨터프로그래밍기초 10
간접참조연산자의해석 -skip 간접참조연산자 : 지정된위치에서포인터의타입에따라값을읽어들인다. int *p = 8; // 위치 8이 p에저장되고, *p는위치8의정수를의미한다. char *pc = 8; // 위치 8 이 pc 에저장되고, *pc 는위치 8 의문자를의미한다. double *pd = 8; // 위치 8이 pd에저장되고, *pd는위치8의실수를의미한다. 컴퓨터프로그래밍기초 11
포인터예제 #1 #include <stdio.h> int i = 3000; int *p = &i; // 변수와포인터연결 printf("&i = %u\n", &i); printf("p p = %u\n", p); // 변수의주소출력 // 포인터의값출력 printf("i = %d\n", i); printf("*p = %d\n", *p); // 변수의값출력 // 포인터를통한간접참조값출력 return 0; &i = 1245024 p = 1245024 i = 3000 *p = 3000 컴퓨터프로그래밍기초 12
포인터예제 #2 #include <stdio.h> char c = 'A'; int i = 10000; double d = 6.78; char *pc = &c; int *pi = &i; double *pd = &d; // 문자형변수정의 // 정수형변수정의 // 실수형변수정의 // 문자형포인터정의및초기화 // 정수형포인터정의및초기화 // 실수형포인터정의및초기화 *pc++ 라고하면안됨 (*pc)++; // 간접참조로 1 증가 *pi = *pi + 1; *pd += 1; // 간접참조로 1 증가 // 간접참조로 1 증가 printf("c = %c\n", c); printf("i = %d\n", i); printf("d = %f\n", d); c=b i = 10001 d = 7.780000 return 0; 컴퓨터프로그래밍기초 13
포인터예제 #3 #include <stdio.h> int i = 10000; // 정수변수정의 int *p p, *q; // 정수형포인터정의 p = &i; q = &i; // 포인터 p 와변수 i 를연결 // 포인터 q와변수i를연결 *p = *p + 1; // 포인터 p를통하여 1 증가 *q = *q + 1; // 포인터 q를통하여 1 증가 printf("i = %d\n", i); return 0; i = 10002 컴퓨터프로그래밍기초 14
포인터사용시주의점 #1 포인터의타입과변수의타입은일치하여야한다. #include <stdio.h> int i; double *pd; pd = &i; *pd = 36.5; // 오류! double 형포인터에 int 형변수의주소를대입 return 0; 컴퓨터프로그래밍기초 15
포인터사용시주의점 #2 초기화가안된포인터를사용하면안된다. int *p; // 포인터 p 는초기화가안되어있음 *p = 100; // 위험한코드 return 0; 컴퓨터프로그래밍기초 16
포인터사용시주의점 #3 포인터가아무것도가리키고있지않는경우에는 NULL로초기화 NULL 포인터를가지고간접참조하면하드웨어로감지할수있다. 포인터의유효성여부판단이쉽다. 컴퓨터프로그래밍기초 17
포인터연산 가능한연산 : 증가, 감소, 덧셈, 뺄셈연산 증가연산의경우증가되는값은포인터가가리키는객체의크기 포인터타입 ++ 연산후증가되는값 char 1 short 2 int 4 float 4 double 8 포인터의증가는일반변수와는약간다릅니다. 가리키는객체의크기만큼증가합니다. 컴퓨터프로그래밍기초 18
증가연산예제 // 포인터의증감연산 #include <stdio.h> char *pc; int *pi; p; double *pd; pc = (char *)10000; pi = (int *)10000; pd = (double *)10000; printf(" 증가전 pc = %d, pi = %d, pd = %d\n", pc, pi, pd); pc++; pi++; pd++; printf(" 증가후 pc = %d, pi = %d, pd = %d\n", pc, pi, pd); return 0; 증가전 pc =10000, pi =10000, pd =10000 증가후 pc = 10001, pi = 10004, pd = 10008 컴퓨터프로그래밍기초 19
포인터의증감연산 컴퓨터프로그래밍기초 20
포인터간의비교 #include <stdio.h> int i, j, *p1, *p2; p1 = &i; p2 = &j; if( p1!= NULL ) printf("p1 p1 이 NULL 이아님 \n"); 포인터와다른포인터비교가능 if( p1!= p2 ) printf("p1과 p2가같지않음 \n"); if( p1 < p2 ) printf("p1이 p2보다앞에있음 \n"); else printf("p1 p1 이 p2 보다앞에있음 \n"); return 0; p1이 NULL이아님 p1과 p2가같지않음컴퓨터프로그래밍 p1이 p2 기초보다앞에있음 21
간접참조연산자와증감연산자 수식 의미 v=*p++ p가가리키는값을 v에대입한후에 p를증가한다. v=(*p)++ p가가리키는값을 v에대입한후에가리키는값을증가한다. v = *++p p를증가시킨후에 p가가리키는값을 v에대입한다. v = ++*p p가가리키는값을가져온후에그값을증가하여 v에대입한다. // 포인터의증감연산 #include <stdio.h> int i= 10; int *pi = &i; i = 10, pi = 0012FF60 i=11,pi=0012ff60 i=11,pi=0012ff60 i = 11, pi = 0012FF64 printf("i = %d, pi = %p\n", i, pi); (*pi)++; printf("i = %d, pi = %p\n", i, pi); printf("i = %d, pi = %p\n", i, pi); *pi++; printf("i = %d, pi = %p\n", i, pi); return 0; 컴퓨터프로그래밍기초 22
포인터와배열 // 포인터와배열의관계 #include <stdio.h> int a[] = 10, 20, 30, 40, 50 ; printf("&a[0] = %u\n", &a[0]); printf("&a[1] = %u\n", &a[1]); printf("&a[2] = %u\n", &a[2]); printf("a = %u\n", a); return 0; &a[0] = 1245008 &a[1] = 1245012 &a[2] = 1245016 a = 1245008 컴퓨터프로그래밍기초 23
포인터와배열 // 포인터와배열의관계 #include <stdio.h> int a[] = 10, 20, 30, 40, 50 ; printf("a = %u\n", a); printf("a + 1 = %u\n", a + 1); printf("*a = %d\n", *a); printf("*(a+1) = %d\n", *(a+1)); return 0; a = 1245008 a + 1 = 1245012 *a = 10 *(a+1) = 20 컴퓨터프로그래밍기초 24
포인터를배열처럼사용 // 포인터를배열이름처럼사용 #include <stdio.h> int a[] = 10, 20, 30, 40, 50 ; int *p; p; p = a; printf("a[0]=%d a[1]=%d a[2]=%d \n", a[0], a[1], a[2]); printf("p[0]=%d p[0] p[1]=%d p[2]=%d \n\n", p[0], p[1], p[2]); p[0] = 60; p[1] = 70; p[2] = 80; printf("a[0]=%d a[1]=%d a[2]=%d \n", a[0], a[1], a[2]); printf("p[0]=%d p[1]=%d p[2]=%d \n", p[0], p[1], p[2]); return 0; a[0]=10 a[1]=20 a[2]=30 p[0]=10 p[1]=20 p[2]=30 a[0]=60 a[1]=70 a[2]=80 컴퓨터프로그래밍 p[0]=60기초 p[1]=70 p[2]=80 25
포인터를사용한방법의장점 인덱스표기법보다빠르다. 원소의주소를계산할필요가없다. int get _ sum1(int m( a[], int n) int get _ sum2(int a[], int n) int i; int i; int sum = 0; int *p; int sum = 0; for(i = 0; i < n; i++ ) sum += a[i]; p = a; return sum; 인덱스표기법사용 for(i = 0; i < n; i++ ) sum += *p++; return sum; 포인터사용 컴퓨터프로그래밍기초 26
배열의원소를역순으로출력 #include <stdio.h> void print_reverse(int a[], int n); int a[] = 10, 20, 30, 40, 50 ; print_reverse(a, 5); return 0; void print_reverse(int a[], int n) int *p = a + n - 1; // 마지막노드를가리킨다. while(p >= a) // 첫번째노드까지반복 printf("%d\n", *p p--); // p 가가리키는위치를출력하고감소 50 40 30 20 10 컴퓨터프로그래밍기초 27
포인터와함수 C 에서의인수전달방법 값에의한호출 : 기본적인방법 참조에의한호출 : 포인터이용 값에의한호출은값만을복사쪐뮰해요. 100 int i = 100; 100 i int sub( int v ) 100 v... sub( i );...... 컴퓨터프로그래밍기초 28
참조에의한호출 함수호출시에포인터를함수의매개변수로전달하는방법 #include <stdio.h> void sub(int *p); int i = 100; 참조에의한호출은주소를복사합니다. sub(&i); return 0; void sub(int *p) *p = 200; int i = 100;... sub( &i ); 96 int sub( int *p )...... 100 i 96 93 94 95 96 97 98 99 100 p 컴퓨터프로그래밍기초 29
swap() 함수 #1 변수 2 개의값을바꾸는작업을함수로작성 #include <stdio.h> void swap(int, int); int a = 100, b = 200; printf("main() a=%d b=%d\n",a, b); swap(a, b); printf("main() a=%d b=%d\n",a, b); return 0; void swap(int x, int y) int tmp; printf("swap() x=%d y=%d\n",x, y); tmp = x; x = y; y = tmp; printf("swap() x=%d y=%d\n",x, y); main() a=100 b=200 swap() x=100 y=200 swap() x=200 y=100 main() a=100 b=200 컴퓨터프로그래밍기초 30
swap() 함수 #2 포인터를이용 #include <stdio.h> void swap(int*, int*); int a = 100, b = 200; printf("main() a=%d b=%d\n",a, b); swap(&a, &b); void swap(int *px, int *py) int tmp; printf("swap() *px=%d *py=%d\n", *px, *py); tmp = *px; *px = *py; *py = tmp; printf("main() a=%d b=%d\n",a, b); return 0; printf("swap() *px=%d *py=%d\n", *px, *py); main() a=100 b=200 swap() *px=100 *py=200 swap() *px=200 *py=100 main() a=200 b=100 컴퓨터프로그래밍기초 31
2 개이상의결과를반환 #include <stdio.h> // 기울기와 y절편을계산 int get_line_parameter(int x1, int y1, int x2, int y2, float *slope slope, float *yintercept) if( x1 == x2 ) return -1; 기울기와 y- 절편을인수로전달 else *slope = (float)(y2 - y1)/(float)(x2 - x1); *yintercept = y1 - (*slope)*x1; return 0; float s, y; if( get_line_parameter(3, 3, 6, 6, &s, &y) == -1 ) printf(" 에러 \n"); else printf(" 기울기는 %f, y절편은 %f\n", s, y); return 0; 기울기는 1.000000, y 절편은 0.000000 컴퓨터프로그래밍기초 32
배열이함수인수인경우 일반변수 vs 배열 // 매개변수 x에기억장소가할당된다. void sub(int x)... // 매개변수 b[] 에기억장소가할당되지않는다. void sub(int b[], int n)... 배열의경우, 크기가큰경우에복사하려면많은시간소모 배열의경우, 배열의주소를전달 컴퓨터프로그래밍기초 33
예제 // 포인터와함수의관계 #include <stdio.h> void sub(int b[], int n); int a[3] = 1,2,3 ; printf("%d %d %d\n", a[0], a[1], a[2]); sub(a, 3); printf("%d %d %d\n", a[0], a[1], a[2]); return 0; void sub(int b[], int n) b[0] = 4; b[1] = 5; b[2] = 6; 1 2 3 4 5 6 컴퓨터프로그래밍기초 34
배열이함수의인수인경우 1/3 컴퓨터프로그래밍기초 35
배열이함수의인수인경우 2/3 컴퓨터프로그래밍기초 36
배열이함수의인수인경우 3/3 컴퓨터프로그래밍기초 37
주의 함수가종료되더라도남아있는변수에대해서만주소를반환하여야한다. ( 사라지는변수의주소를반환하면안된다.) 지역변수의주소를반환하면, 함수가종료되면사라지기때문에오류 int *add(int x, int y) int result; 지역변수 result는함수가종료되면소멸되므로그주소를반환하면안된다.!! result = x + y; return &result; 컴퓨터프로그래밍기초 38
포인터사용의장점 연결리스트나이진트리등의향상된자료구조를만들수있다. A N C D E A C D E B B 메인메모리 메인메모리 참조에의한호출 포인터를매개변수로이용하여함수외부의변수의값을변경할수있다. 동적메모리할당 17 장에서다룬다. (malloc() 함수에대한내용 ) 컴퓨터프로그래밍기초 39
응용예제 #1 한국 미국일본 포인터를통한간접접근의장점 burger_kor[] burger_usa[] burger_jap[] p_burger 현재설정된나라의햄버거의가격을출력 #include <stdio.h> int burger_kor[3]= 3000, 2000, 4000 ; int burger_usa[3]= 3500, 2600, 5000 ; int burger _jap[3]= 3200, 2700, 4500 ; int country; int *p_burger=null; 포인터를사용하여현재사용자가선택한국가를기억하고있다. printf(" 지역을입력하시요 :"); scanf("%d", &country); if( country == 0 ) p_burger = burger_kor; else if( country == 1 ) p_burger = burger_usa; usa; else p_burger = burger_jap; printf(" 현지역에서의햄버거가격 :"); printf("%d %d %d\n", p_burger[0],p_burger[1],p_burger[2]); p burger[1] p burger[2]); return 0; 컴퓨터프로그래밍기초 40
버블정렬 -skip void bubble_sort(int *p, int n) int i, scan; // 스캔회수를제어하기위한루프 for(scan = 0; scan < n-1; scan++) // 인접값비교회수를제어하기위한루프 for(i = 0; i < n-1; i++) // 인접값비교및교환 if( p[i] > p[i+1] ) swap(&p[i], &p[i+1]); void swap(int *px, int *py) 포인터를통하여배열원소교환 int tmp; tmp = *px; *px = *py; *py = tmp; 컴퓨터프로그래밍기초 41
배열의최소값과최대값 #include <stdio.h> #define SIZE 10 void get_max_min(int list[], int size, int *pmax, int *pmin); int max, min; int grade[size] = 3, 2, 9, 7, 1, 4, 8, 0, 6, 5 ; get_max_min(grade, SIZE, &max, &min); printf(" 최대값은 %d, 최소값은 %d입니다.\n", max, min); return 0; 컴퓨터프로그래밍기초 42
배열의최소값과최대값 void get_max_min(int list[], int size, int *pmax, int *pmin) int i, max, min; max = min = list[0]; for(i = 1;i < size; i++) if( list[i] > max) max = list[i]; if( list[i] < min) min = list[i]; *pmax = max; *pmin = min; // 첫번째원소를최대, 최소값으로가정 // 두번째원소부터최대, 최소값과비교 // list[i] 가최대값보다크면 // list[i] 를최대값으로설정 // list[i] 가최소값보다작으면 // list[i] 를최소값으로설정 최대값은 9, 최소값은 0 입니다. 컴퓨터프로그래밍기초 43
Q & A 컴퓨터프로그래밍기초 44