Download presentation
Presentation is loading. Please wait.
Published by祥舒 卫 Modified 6년 전
0
C언어: 포인터 (Pointers)
1
포인터란? 사전적 의미로써 지시자 혹은 가리키는 것으로 풀이할 수 있으나, C프로그래밍 언어에서는 메모리의 주소를 저장하는 변수이다. 포인터 자체가 하나의 변수이기 때문에 포인터도 메모리 내에서 선언이 되며 일반 상수를 저장하는 변수가 아닌 주소값을 저장하는 변수라는 점에서 일반 변수와 구별된다. 포인터란 일반 변수의 주소값을 저장하기 위한 용도로 사용되며, 이 포인터를 가지고 변수에 접근할 수 있다.
2
변수와 포인터 변수는 일반적으로 상수 등을 저장할 때 사용되며, 변수는 메모리에 생성될 때 주소값을 가지고 있다.
주소를 사용자가 읽어오고자 할 때 사용하는 것이 바로 포인터 변수이다.
3
포인터 변수의 선언 포인터 변수를 선언할 때는 일반적인 변수의 명명법과 같이 키워드는 사용할 수 없으며 포인터 변수명 앞에 * 표시를 붙이는 것을 규칙으로 한다.
4
포인터 변수의 자료형 val 이란 int 형 변수의 주소값을 pVal 이라고 하는 포인터 변수에 저장하고자 한다면, 이 두 자료형을 일치시켜야 한다.
5
포인터 변수의 사용 pVal 이라고 하는 포인터 변수를 * 기호를 활용하여 선언한 후 val이 위치하고 있는 메모리의 주소를 저장 pVal 포인터 변수를 사용하여 val 변수의 주소뿐만 아니라, val 변수가 담고 있는 int형 값도 읽고 쓸 수 있다.
6
포인터를 활용하여 변수 읽고 쓰기 포인터 변수를 이용하여 포인터가 가리키고 있는 주소에 존재하는 변수값 자체를 읽거나 쓸 수 있다.
7
포인터 변수의 활용 포인터를 이용하여 포인터가 가리키는 변수에 값을 쓰거나 읽기 위해서는 * 기호를 사용한다.
8
포인터 사용시 주의사항 - 1 포인터는 선언과 동시에 초기화하라.
9
포인터 사용시 주의사항 - 1 초기화하지 않은 포인터를 사용하였을 때의 경고 메시지
초기화할 주소가 있지 않은 경우에는 보통 포인터에 0 값을 대입하여 초기화한다.
10
포인터 사용시 주의사항 - 2 포인터에 일반 상수를 대입하지 않는다. 포인터에는 변수의 주소값만 존재할 수 있다.
이는 포인터를 초기화하지 않고, 임의의 주소를 대입한 것과 같은 결과를 초래할 수 있다. 0 이외의 값은 대입하지 않도록 한다.
11
포인터 사용시 주의사항 - 3 포인터를 활용하여 포인터가 가리키는 값을 증가 및 감소시킬 때 연산자 우선순위를 고려해야 한다.
12
예제 9-1 간단한 포인터 활용 프로그램 포인터를 활용하여 변수에 값을 대입하고 증감연산자를 사용하며 변수에서 값을 읽어 오는 프로그램을 작성한다.
13
예제 9-1 2차원 배열을 활용한 문자열 배열을 출력하는 프로그램
// C_EXAMPLE\ch9\ch9_project1\simplepointer.c #include <stdio.h> void main(void) { char ch = 10; char *p = &ch; // 포인터 p에 ch의 주소를 대입 printf("ch의 주소는 %p, 값은 %d 입니다. \n", p, *p); *p = 20; // p가 가리키는 주소의 값에 20을 대입 printf("바뀐 ch의 값은 %d 입니다.\n", *p); ch = (*p)++; // p가 가리키는 값을 하나 증가시킨다. printf("%d\n", ch); ch = ++*p; // p가 가리키는 값을 1증가시킨 후 ch에 대입 printf("%d %p\n", ch, p); ch = *p++; // p가 가리키는 값을 ch에 대입하고 p(주소값)를 증가시킴 } // main() 포인터는 *의 기호를 사용하며, 포인터만이 주소값을 저장함 %p는 포인터의 값을 출력함 p가 가리키는 주소의 값을 불러옴 포인터를 활용하여 값을 대입할 수도 있음 p가 가리키는 값을 ch에 다시 저장한 후 p가 가리키는 값을 1증가시킨다. 결과적으로 p가 가리키는 곳은 ch이므로, ch의 값이 1증가 되게 된다. p가 가리키는 값을 1증가시킨 후 그 값을 다시 ch에 대입한다. p가 가리키는 값을 ch에 저장한 후 p의 값 자체를 1증가시킨다. p가 가리키는 주소가 1 증가했음을 알 수 있음.
14
예제 9-1 2차원 배열을 활용한 문자열 배열을 출력하는 프로그램 ch의 주소 16진수 값으로 32비트로 구성됨 *ch
ch = ++*p; p의 값이 1증가되었음을 확인할 수 있다. ch = (*p)++; ch = *p++;
15
값에 의한 호출 (call by value) 값을 매개체로 하여 함수에 인수를 전달하는 방식
16
참조에 의한 호출 (call by reference)
주소값을 매개체로 하여 함수를 호출하는 방식
17
값에 의한 호출인 경우의 변수 관계 함수에 인수를 전달한 후 함수 내부의 몸체에서 사용되는 값은 바로 함수가 호출되고 나서 메모리에 새롭게 생성되는 지역변수이다. 함수로 전달되는 이 매개체가 값만 필요로 한 것이기 때문에 그 값을 그대로 메모리의 새로운 영역에 복사하여 사용된다.
18
참조에 의한 호출인 경우의 변수 관계 함수를 호출할 때 값 대신에 주소를 넘겨주기 때문에 원본 그대로 함수 내에서 조작한다는 차이가 있다. 함수 내에서 이 값을 조작하면 호출할 때 매개체의 메모리를 그대로 참조하기 때문에 함수가 종료되어도 그 값이 변경될 수 있다.
19
값에 의한 호출과 참조에 의한 호출을 사용하여 2개의 변수값을 변경하는 프로그램
예제 9-2 값에 의한 호출과 참조에 의한 호출을 사용하여 2개의 변수값을 변경하는 프로그램 값에 의한 호출과 참조에 의한 호출을 사용하여 2개의 변수값을 변경하는 프로그램을 작성한다.
20
예제 9-2 값에 의한 호출과 참조에 의한 호출을 사용하여 2개의 변수값을 변경하는 프로그램
// C_EXAMPLE\ch9\ch9_project2\swap.c #include <stdio.h> void swap(int, int, int*, int*); // 함수원형선언 void main(void) { int a = 10, b = 20; int c = 100, d = 200; swap(a, b, &c, &d); // swap() 함수호출 printf("a=%d, b=%d, c=%d, d=%d \n", a, b, c, d); } // main() 자료형과 *기호 사이에 공백이 없어도 된다. 인수 4개를 갖는 함수원형선언 인수가 포인터인 경우 주소값을 넘김
21
예제 9-2 값에 의한 호출과 참조에 의한 호출을 사용하여 2개의 변수값을 변경하는 프로그램
x, y 변수에 a, b 값이 복사되어 함수 수행 void swap(int x, int y, int *px, int *py) // 함수정의 { int temp; // 임시 저장 공간 // 일반 변수의 swap temp = x; x = y; y = temp; // 포인터 변수의 swap temp = *px; *px = *py; *py = temp; } // swap() c, d가 존재하는 주소값을 참조하여 함수 수행 x에 y를 바로 대입하면, x값이 소멸되기 때문에 임시 변수를 사용한다. 각 주소가 가지고 있는 값을 서로 바꾸어 해당 주소에 대입하기 때문에 함수가 종료되어도 주소에 있는 값은 변함이 없다.
22
예제 9-2 값에 의한 호출과 참조에 의한 호출을 사용하여 2개의 변수값을 변경하는 프로그램 a, b는 변경되지 않았음
c, d는 서로 변경되었음
23
인수를 활용한 값의 반환 2개 이상의 반환을 얻고자 할때 사용
함수를 호출할 때 인수로써 주소값을 넘겨주고 함수의 몸체에서 연산을 수행하여 해당 주소값에 어떠한 값을 대입해 주면, 함수가 종료될 때 그 주소값에는 함수가 수행될 때의 연산 결과가 저장된다.
24
인수를 활용하여 함수 수행 결과를 얻어오는 프로그램
예제 9-3 인수를 활용하여 함수 수행 결과를 얻어오는 프로그램 3개의 변수를 선언하고, 이들 각각의 주소를 저장하는 포인터 변수를 선언한다. func()라는 함수에 이들 포인터 변수를 넘겨주어 각각 이들 포인터가 가리키는 값에 2를 곱하여 저장하는 함수를 작성한다.
25
예제 9-3 인수를 활용하여 함수 수행 결과를 얻어오는 프로그램
// C_EXAMPLE\ch9\ch9_project3\pointerargfunction.c #include <stdio.h> void func(int*, int*, int*); // 함수원형선언 void main(void) { int a = 10, b = 20, c = 30; int *pa = &a, *pb = &b, *pc = &c; // 포인터 변수선언 및 주소할당 func(pa, pb, pc); // 포인터를 인수로 하는 함수호출 printf("a = %d, b = %d, c = %d\n", a, b, c); } // main() void func(int *x, int *y, int *z) // 함수정의 *x *= 2; // *x = *x * 2 *y *= 2; *z *= 2; } // func() 3개의 포인터 변수를 인수로 하는 함수원형선언 a, b, c 각각의 주소를 저장하는 포인터 변수의 선언 func() 함수호출 a, b, c 각 주소값을 넘겨 받음 a, b, c 의 각 주소에 존재하는 값에 2를 곱해 다시 저장함
26
예제 9-3 인수를 활용하여 함수 수행 결과를 얻어오는 프로그램 ch의 주소 16진수 값으로 32비트로 구성됨
27
포인터와 배열의 관계 포인터를 사용하는 또 하나의 목적은 바로 배열에 접근할 때 보다 편리하게 배열의 원소들에 접근할 수 있기 때문이다. 왜냐하면 배열의 경우 각 배열의 원소들이 메모리에 존재하는 주소가 규칙적으로 할당되기 때문이다.
28
배열의 시작주소 포인터 배열명은 배열의 첫 원소의 시작주소를 가지고 있는 포인터이다. 그러나 그 자신의 주소 값은 변경할 수 없다.
29
배열의 원소 주소값 할당 규칙 배열 원소들의 주소값은 메모리에 연속적으로 배치된다. 이때 주소값은 자료형의 크기에 따라 증가하게 된다. 예를 들어 char형인 경우에는 주소값이 1씩 증가하게 된다.
30
자료형에 따른 주소의 길이 자료형 주소 길이 char 1 short 2 int 4 float D2ouble 8
배열을 선언한 자료형에 따라 배열의 주소 할당 길이가 달라진다. 자료형 주소 길이 char 1 short 2 int 4 float D2ouble 8
31
자료형에 따른 배열 주소의 길이
32
자료형에 따른 배열의 길이 할당의 예 자료형에 따른 각 배열의 선언과 그에 해당하는 주소의 연속적인 할당 규칙
33
포인터의 증감(++,--) 크기 자료형 증감크기 char 1 short 2 int 4 float D2ouble 8
포인터에 증감연산자를 사용하면, 일반적으로 +1, -1 되는 것이 아니라 자료형에 따라 증감되는 값이 달라진다. 자료형 증감크기 char 1 short 2 int 4 float D2ouble 8
34
자료형에 따른 증감 예 char *p1; short *p2; int *p3; float *p4; double *p5;
자료형에 따라 증감되는 값이 다르다 char *p1; short *p2; int *p3; float *p4; double *p5; p1++; // 1씩 증가 p2++; // 2씩 증가 p3++; // 4씩 증가 p4++; // 4씩 증가 p5++; // 8씩 증가
35
배열을 포인터로 표시 포인터를 사용하여 배열을 표현할 경우에 a[0]의 주소인 &a[0]는 배열의 이름이 시작주소를 가지므로 a가 된다. 따라서 a[2]의 주소는 a+2가 되고, a[2]의 값은 *(a+2)와 같게 된다.
36
네 종류의 배열을 선언하고, 각 배열 원소의 주소값과 포인터 증감을 확인하는 프로그램
예제 9-4 네 종류의 배열을 선언하고, 각 배열 원소의 주소값과 포인터 증감을 확인하는 프로그램 char형, short형, int형, double형 배열 4개를 각각 선언한 후에 해당 배열의 주소값을 출력하고, 포인터를 이용하여 각 배열의 원소를 출력하는 프로그램을 작성한다.
37
예제 9-4 네 종류의 배열을 선언하고, 각 배열 원소의 주소값과 포인터 증감을 확인하는 프로그램
// C_EXAMPLE\ch9\ch9_project4\arraypointer1.c #include <stdio.h> void main(void) { char ch[4] = {'a', 'b', 'c', 'd'}; short s[4] = {1, 2, 3, 4}; int i[4] = {1, 2, 3, 4}; double d[4] = {1, 2, 3, 4}; int k; int *P = &k; // 포인터의 증가값이 1이 아닌지를 확인 printf("P = %x ", P++); printf("P++ = %x\n\n", P); 4종류의 배열을 선언 k의 주소를 포인터 P가 저장 포인터 P는 int형이기 때문에 주소를 4개 차지하여 1이 아닌 4값이 증가됨
38
예제 9-4 네 종류의 배열을 선언하고, 각 배열 원소의 주소값과 포인터 증감을 확인하는 프로그램
배열의 이름은 배열의 시작주소를 가지고 있는 포인터이다. // 배열의 이름이 배열의 시작주소값인지를 확인 printf("ch=%x, s=%x, i=%x, d=%x \n\n", ch, s, i, d); // 각 배열의 원소들이 갖는 주소값이 연속적인지 확인 for(k = 0; k < 4; k++) { printf("ch[%d]=%x, s[%d]=%x, i[%d]=%x, d[%d]=%x \n", \ k,&ch[k], k,&s[k], k,&i[k], k,&d[k]); } // for // 포인터를 이용하여 각 배열의 원소에 접근 printf("\n*ch=%c, *(s+1)=%d, *(i+2)=%d, *(d+3)=%d \n", *ch, *(s+1), *(i+2), *(d+3)); } // main() k값을 0부터 4까지 증가시켜 가면서 각 배열 원소의 주소값을 출력한다. \ 기호를 사용하면, 여러 줄에 걸쳐 소스 코드를 기록할 수 있다. 포인터를 사용하여, 각 주소값을 증가시켜 원소에 접근할 수 있다. *ch==ch[0], *(s+1) == s[1], *(i+2)==i[2], *(d+3)==d[3]
39
예제 9-4 값에 의한 호출과 참조에 의한 호출을 사용하여 2개의 변수값을 변경하는 프로그램
int *P의 경우 P++는 4씩 증가됨 배열명은 배열의 시작주소값을 갖는 포인터 1씩 증가 2씩 증가 8씩 증가 4씩 증가 포인터를 사용하여 배열의 원소에 접근
40
예제 9-5 6개의 배열을 선언하고, 각 배열의 원소를 접근하는 프로그램
포인터를 사용하여 배열의 원소에 접근하는 방법이 여러 가지가 있는데, 이 중 각 배열의 주소를 하나씩 증가시키면서, 원소에 접근하는 프로그램을 작성한다.
41
예제 9-5 6개의 배열을 선언하고, 각 배열의 원소를 접근하는 프로그램
// C_EXAMPLE\ch9\ch9_project5\arraypointer2.c #include <stdio.h> void main(void) { int *p; int a[6] = {50, 60, 70, 80, 90, 100}; p = &a[0]; // p = a; printf("a[2] = %d\n", *(a+2)); // a[2] printf("p = %d\n", *p); // a[0] printf("p = %d\n", *++p); // a[1] printf("p = %d\n", ++*p); // ++a[1] printf("p = %d\n", *p++); // a[1] 이후 a[2]로 포인터 이동 printf("p = %d\n\n", *p + 4); // a[2] + 4 } // main() a배열의 주소를 p에 저장함 a의 주소를 두 개 증가한 곳의 원소 p의 주소를 1증가 시킨 곳의 원소 p의 주소를 1증가 시킨 곳의 원소를 1증가시킴 현재 p의 주소가 가리키는 값을 출력 후 주소를 1증가시킴 p가 가리키는 값에 4를 더함
42
예제 9-5 6개의 배열을 선언하고, 각 배열의 원소를 접근하는 프로그램 *p *++p ++*p *p++ *p + 4
43
이차원 배열을 포인터로 접근 다차원 배열은 포인터로 표현하면 쉽다.
이 배열은 a[0][0] 부터 차례대로 포인터의 값을 하나씩 증가시키면 각 원소에 접근할 수 있다.
44
포인터를 이용한 2차원 배열의 표현 2차원 배열을 포인터를 이용하여 나타낸 각 원소
45
예제 9-6 2차원 배열을 포인터로 이용하여 각 원소들을 출력하는 프로그램
char형의 2차원 배열 a[3][4]를 선언하고 for문을 이용하여 각 원소들을 출력하는 프로그램을 작성한다.
46
예제 9-6 2차원 배열을 포인터로 이용하여 각 원소들을 출력하는 프로그램
// C_EXAMPLE\ch9\ch9_project6\arraypointer3.c #include <stdio.h> void main(void) { char a[3][4] = { // 4x3 형태의 2차원 배열 선언 {1, 2, 3, 4}, {11, 12, 13, 14}, {21, 22, 23, 24}}; char *P = a; // 배열명 a는 &a[0]와 같음 int i; // a 배열의 크기만큼 루프를 돌며 각 원소를 출력 for(i = 0; i < sizeof(a); i++) printf("a[][] = %d\n", *(P+i)); } // for } // main() 2줄에 걸쳐 2차원 배열을 선언 만일 포인터 P에 a[1]의 주소를 대입하면, a[1][0]부터 출력이 된다. char형 배열이므로, 배열의 크기가 곧 길이이다. i가 증가할수록 각 배열의 원소를 차례대로 가리킨다.
47
*P 부터 *(P+11) 까지의 2차원 배열의 원소값들이 출력됨
예제 9-6 2차원 배열을 포인터로 이용하여 각 원소들을 출력하는 프로그램 *P 부터 *(P+11) 까지의 2차원 배열의 원소값들이 출력됨
48
일반문자배열
49
포인터를 이용한 문자배열
50
예제 9-7 포인터를 이용하여 문자열을 표현하는 프로그램 포인터를 이용하여 문자열을 표현하는 프로그램을 작성한다.
51
예제 9-7 포인터를 이용하여 문자열을 표현하는 프로그램
// C_EXAMPLE\ch9\ch9_project7\arraypointer4.c #include <stdio.h> void main(void) { int k; char *s = "string"; printf("s의 시작주소 : %d\n", s); printf("s의 문자열 : %s\n\n", s); for(k = 0; k < 7; k++) printf("*(s + %d) : %c\n", k, *(s + k)); printf("\n"); } // main() 문자배열을 선언, 자동으로 ‘\0’ 문자 추가됨 k가 0 ~ 6까지 7번 수행 *s, *(s+1) … *(s+6)
52
예제 9-7 포인터를 이용하여 문자열을 표현하는 프로그램 문자열의 시작주소 ‘\0’ 문자는 표시되지 않음
53
함수호출시 인수에 포인터를 사용하는 경우(1차원 배열)
54
함수호출시 인수에 포인터를 사용하는 경우(2차원 배열)
55
함수에 1차원 및 2차원 배열을 인수로 전달하는 프로그램
예제 9-8 함수에 1차원 및 2차원 배열을 인수로 전달하는 프로그램 1차원 배열과 2차원 배열의 인수를 출력하는 프로그램을 작성하고, 2차원 배열의 각 원소들의 합을 구하는 프로그램을 작성한다.
56
함수에 1차원 및 2차원 배열을 인수로 전달하는 프로그램
예제 9-8 함수에 1차원 및 2차원 배열을 인수로 전달하는 프로그램 // C_EXAMPLE\ch9\ch9_project8\arraypointer5.c #include <stdio.h> // 함수원형선언 void print_array(int *m); void total_array(int (*k)[4]); void main(void) { int m[5] = {5, 15, 25, 35, 45}; int k[3][4] = {{2, 4, 6 ,7}, {4, 1, 5, 6}, {3, 6, 5, 2}}; print_array(m); total_array(k); } // main() 1차원 배열을 인수로 하는 함수원형선언 2차원 배열을 인수로 하는 함수원형선언 배열의 이름을 인수로 넘김
57
함수에 1차원 및 2차원 배열을 인수로 전달하는 프로그램
예제 9-8 함수에 1차원 및 2차원 배열을 인수로 전달하는 프로그램 1차원 배열을 매개변수로 하는 함수의 정의 void print_array(int *n) { int a; for(a = 0; a < 5; a++) printf("n[%d] = %d\n", a, n[a]); printf("\n"); } // print_array() void total_array(int (*array)[4]) int i, j, sum = 0; for(i = 0; i < 3; i++) for(j = 0; j < 4; j++) sum = sum + array[i][j]; printf("2차원 배열 원소의 총합 : %d\n\n", sum); } // total_array() 2차원 배열을 매개변수로 하는 함수의 정의
58
함수에 1차원 및 2차원 배열을 인수로 전달하는 프로그램
예제 9-8 함수에 1차원 및 2차원 배열을 인수로 전달하는 프로그램 print_array() 함수의 결과 total_array() 함수의 결과
59
이중 포인터 이중 포인터는 포인터의 주소값을 또 다른 포인터가 저장하고 있는 형태이다.
60
이중 포인터의 변수 접근 방법 이중 포인터 q를 이용하여 변수 ch의 값을 읽어오기 위해서는 * 기호를 2개 사용하면 된다.
61
이중 포인터의 선언 이중 포인터를 선언시 * 기호를 이용하여 포인터를 선언하며 *의 개수를 감안하여 포인터를 선언한다.
62
다중 포인터 삼중 이상의 포인터는 잘 사용하지는 않으나, 이중 포인터와 개념은 비슷
다중포인터는 2개 이상의 포인터가 중간에 개입하여 변수를 지칭하도록 한다.
63
예제 9-9 다중 포인터 프로그램 이중 포인터와 사중 포인터를 이용하여 변수 ch의 값을 출력하는 프로그램을 작성한다.
64
예제 9-9 다중 포인터 프로그램 // C_EXAMPLE\ch9\ch9_project9\multipointer.c
#include <stdio.h> void main(void) { char ch = 10; // 일반 변수 char *p = &ch; // 일반 포인터 char **q = &p; // 이중 포인터 char ***r = &q; // 삼중 포인터 char ****s = &r; // 사중 포인터 // 각 변수의 주소를 출력 printf("p = %p, q = %p, r = %p, s = %p, &s = %x \n", p, q, r, s, &s); // 이중 포인터와 사중 포인터를 이용하여 변수 ch값 출력 printf("**q = %d, ****s = %d \n", **q, ****s); } // main() 변수를 선언할 때도 몇 중 포인터인지 명시해야 함 각 주소값들은 4바이트의 길이를 갖고, 연속적이다. 두 개 모두 변수 ch의 값을 가리킨다.
65
예제 9-9 다중 포인터 프로그램 각 변수의 주소값이 연속적이며, 그 길이는 4이다.
printf()문에서 %p를 쓰지 않고 %x를 사용했을 때 차이가 난다. 2개의 값은 모두 ch를 가리킨다.
66
포인터 배열이란 ? 포인터 배열(pointer array)은 배열의 원소를 주소값으로 사용한다.
포인터 변수 자체를 배열로써 사용하는 것으로 배열의 각 원소들이 모두 주소값이다. 보통 포인터 배열은 문자열을 배열로써 만들기 위하여 사용하는 것 포인터 배열 입장에서는 각 문자열들이 포인터 배열의 원소가 된다.
67
char형 문자 2차원 배열
68
포인터 배열의 선언과 메모리 할당 규칙 4개의 영역에 대한 메모리 할당이 이뤄지지 않으므로, 보다 효율적으로 메모리를 관리할 수 있다.
69
포인터 배열의 선언 및 초기화 방법 포인터 배열의 선언 방법 포인터 배열의 초기화 방법
70
예제 9-10 다중 포인터 프로그램 문자열 포인터 배열을 선언하고, 각 원소 및 문자열을 표현할 수 있는 여러 가지 방법에 대한 프로그램을 작성한다.
71
예제 9-10 다중 포인터 프로그램 // C_EXAMPLE\ch9\ch9_project10\pointerarray1.c
#include <stdio.h> void prn(char *name[ ]); // void prn(char **name); void main(void) { // 포인트 배열의 선언 및 초기화 char *s[] = { "My", "name", "is", "Joey“ }; // 첫 번째 문자열 printf("s[0] = %s \n", s[0]); // 두 번째 문자열 printf("*(s+1) = %s \n", *(s+1)); 총 4개의 문자열이므로, s[0] ~ s[3]까지의 행이 있다. “My”의 문자열 중 M이 위치한 주소를 나타낸다. “name”의 문자열 중 n이 위치한 주소를 나타낸다.
72
예제 9-10 다중 포인터 프로그램 // 세 번째 문자열 중 두 번째 문자
printf("s[2][1] = %c \n", s[2][1]); // 네 번째 문자열 중 첫 번째 문자 printf("**(s+3) = %c \n\n", **(s+3)); prn(s); } // main() void prn(char *pname[ ]) // void prn(char **pname) { printf("name = %s\n\n", pname[3]); } // prn() “is” 문자열 중 두 번째 문자 ‘s’를 가리킨다. “Joey” 문자열의 첫 번째 문자 ‘J’를 가리킨다. “Joey” 문자열을 가리킨다.
73
예제 9-10 다중 포인터 프로그램 세 번째 포인터 배열 원소의 두 번째 문자 ‘s’
네 번째 포인터 배열 원소의 첫 번째 문자 ‘J’ prn() 함수의 결과 : pname[3]의 출력물
74
예제 9-11 다중 포인터 배열 프로그램 다중 포인터 배열 프로그램을 작성한다.
75
예제 9-11 다중 포인터 배열 프로그램 // C_EXAMPLE\ch9\ch9_project11\pointerarray2.c
#include <stdio.h> char *p[] = {"DATA", "STRUCTURE", "COMPUTER", "ALGORITHM"}; char **pp[] = {p + 3, p + 2, p + 1, p}; char ***ppp = pp; void main(void) { printf("**++ppp + 1 = %s\n", **++ppp + 1); printf("*--*++ppp = %s\n", *--*++ppp); printf("*ppp[-2] + 2 = %s\n", *ppp[-2] + 2); printf("ppp[-2][-2] = %s\n\n", ppp[-2][-2]); } // main() 연산순서가 오른쪽에서 왼쪽으로 *(ppp - 2)와 같다. *(*(ppp - 2)결과) - 2)
76
예제 9-11 다중 포인터 배열 프로그램 연산순서가 오른쪽에서 왼쪽 *(ppp - 2) + 2과 같다.
77
함수 포인터란? 변수를 가리키는 포인터 이외에도 함수를 가리키는 포인터가 존재
78
함수명에 담긴 주소 함수가 위치하는 주소는 함수명 자체가 바로 주소값이다. 이는 배열명 자체가 배열의 주소값을 갖는 것과 마찬가지이다.
79
함수 포인터의 선언 방법 함수 포인터는 함수에 대한 주소값을 저장할 수 있는 포인터이므로, 저장하고자 하는 주소에 위치하는 함수와 함수 포인터의 형식은 일치해야 한다.
80
함수 포인터의 선언 예
81
함수 포인터가 함수를 가리키도록 하는 방법 함수 포인터를 선언한 이후에 함수 포인터가 원형 함수를 가리키고자 할 때에는 일반적인 변수와 마찬가지로 함수명 자체가 주소값을 가지고 있기 때문에 & 기호를 생략한다.
82
함수 포인터를 이용한 함수호출 함수 포인터를 이용하여 실제 함수를 호출하는 방법 2가지
83
예제 9-12 함수 포인터를 이용한 두 수의 합을 구하는 프로그램
2개의 인수를 받아 두 수의 합을 반환하는 함수를 작성한 뒤에 함수 포인터를 이용하여 함수를 호출하고, 두 수를 더한 결과값을 화면에 출력하는 프로그램을 작성한다.
84
예제 9-12 함수 포인터를 이용한 두 수의 합을 구하는 프로그램
// C_EXAMPLE\ch9\ch9_project12\functionpointer.c #include <stdio.h> int sum(int, int); // 함수원형선언 void main(void) { int (*pSum)(int, int); // 함수 포인터 선언 int ans; pSum = sum; // 함수 포인터 연결 ans = pSum(10, 20); // 함수호출 printf(" = %d\n", ans); } // main() int sum(int a, int b) // 함수의 정의 return a + b; // 더한 값 반환 } // sum() 연결하고자 하는 함수의 원형과 일치시켜야 함 함수명 자체가 주소를 가지고 있기 때문에 & 기호를 생략함 ans = (*pSum)(10, 20); 으로 사용해도 됨
85
예제 9-12 함수 포인터를 이용한 두 수의 합을 구하는 프로그램 sum 함수를 호출한 것과 같다.
86
함수 포인터 배열 함수 포인터를 사용하여 얻는 이점은 함수 포인터 배열을 사용하여 여러 개의 함수를 간결한 코드로 접근할 수 있다는 데에 있다.
87
함수 포인터 배열 선언 방법
88
함수를 호출하는 방법
89
예제 9-13 함수 포인터 배열을 이용하여 원하는 함수를 호출하는 프로그램
사용자로부터 사칙연산 중 한 개의 선택 값을 1부터 4까지의 숫자로 입력받은 뒤 해당 연산을 수행하는 4개의 함수 중 한 개를 호출하여 그 결과를 화면에 출력하는 프로그램을 작성한다.
90
예제 9-13 함수 포인터 배열을 이용하여 원하는 함수를 호출하는 프로그램
// C_EXAMPLE\ch9\ch9_project13\functionpointerarray.c #include <stdio.h> // 함수의 정의 int sum(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } int multiply(int a, int b) { return a * b; } int divide(int a, int b) { return a / b; } void main(void) { int (*funcP[4])(int, int); // 함수 포인터 배열 선언 int mode, ans; // 함수 포인터 배열과 각 함수들을 연결 funcP[0] = sum; funcP[1] = subtract; funcP[2] = multiply; funcP[3] = divide; 함수원형선언이 생략됨(int형인 경우) 함수 포인터 배열에 연결하기 위해서는 모든 함수의 형태가 일치해야 함 함수 포인터 배열 선언 4개의 함수가 funcP 함수 포인터 배열에 등록되었다.
91
예제 9-13 함수 포인터 배열을 이용하여 원하는 함수를 호출하는 프로그램 printf("모드를 선택하세요.\n");
printf(" 1. 덧셈\n 2. 뺄셈\n 3. 곱셈\n 4. 나눗셈\n ===> "); scanf("%d", &mode); // 사용자로부터 숫자를 입력 받음 if(mode >= 1 && mode <= 4) { // 1부터 4까지의 입력인지를 비교 ans = funcP[mode-1](10, 5); // 함수 배열에 연결된 함수를 호출 printf("결과는 %d 입니다.\n", ans); } // if else // 1부터 4까지의 입력이 아닌 경우 printf("잘못 선택하였습니다.\n"); } // main() 사용자로부터 숫자 한 개를 입력받아 mode 변수에 저장 mode가 1~4 이내의 값인지 비교 funcP[첨자](인수, 인수)의 형태를 띄고 함수를 호출함
92
예제 9-13 함수 포인터 배열을 이용하여 원하는 함수를 호출하는 프로그램
funcP[2](10,5)가 호출되어 multiply() 함수로 부터 50을 반환받아 출력되었다.
93
void 포인터란? 포인터의 일종이며 일반적으로 사용하는 int*, char*, double* 등의 포인터와는 달리 특별한 자료형이 정해져 있지 않은 포인터이다. 어떠한 변수든 그 자료형에 상관없이 아무 주소값이나 저장할 수 있다.
94
간접 참조 연산자를 사용하여 값을 참조할 수 없다.
95
증감 연산자를 사용할 수 없다.
96
예제 9-14 모든 자료형에 대해 두 변수의 값을 변경시키는 함수를 작성하는 프로그램
어떠한 자료형이라도 2개의 변수 a, b를 선언한 후에 값을 대입한 뒤 swap() 함수를 호출하여 a와 b의 값을 변경시키는 프로그램을 작성한다.
97
예제 9-14 모든 자료형에 대해 두 변수의 값을 변경시키는 함수를 작성하는 프로그램
// C_EXAMPLE\ch9\\ch9_project14\voidpointer.c #include <stdio.h> // swap() 함수정의 // src에 있는 공간의 값과 des가 가리키는 공간의 값을 size 바이트만큼 교환 void swap(void *src, void *des, int size) { char *p1 = (char*)src; // src void 포인터를 char형 포인터로 형변환 char *p2 = (char*)des; // des void 포인터를 char형 포인터로 형변환 char temp; int i; for(i = 0; i < size; i++){ temp = *p1; // p1이 가리키는 공간의 1바이트 값을 temp에 저장 *p1 = *p2; // p2가 가리키는 공간의 1바이트 값을 p1에 저장 *p2 = temp; // temp의 값을 p2가 가리키는 공간에 저장 ++p1; ++p2; } // for } // swap() 모든 자료형을 가리킬 수 있도록 void 포인터를 사용 반드시 형변환해야 한다. char* 형으로 변환하는 이유는 주소값을 참조하여 값을 변경하는데, 주소를 1바이트 단위로 접근하면 모든 자료형에 대하여 값의 변경이 가능하기 때문이다. p1과 p2는 함수의 인수 src와 des가 담고 있는 주소를 가지고 있다. 따라서 1바이트씩 size 크기만큼 루프를 돌며 1바이트 단위로 값을 바꾼다. p1, p2가 가리키는 주소를 1씩 증가시킨다.
98
예제 9-14 모든 자료형에 대해 두 변수의 값을 변경시키는 함수를 작성하는 프로그램 void main(void) {
int a = 0x ; int b = 0x ; printf("a = %#x, b = %#x\n", a, b); // swap() 함수호출 swap(&a, &b, sizeof(int)); } // main() a와 b의 주소값을 함수로 넘긴다. int의 경우 4바이트
99
예제 9-14 모든 자료형에 대해 두 변수의 값을 변경시키는 함수를 작성하는 프로그램
원래의 a, b 값 : 4바이트의 정수이다. 변경된 a, b의 값이다.
100
명령라인 인수란? 프로그램이 실행될 때 2개의 인수를 프로그램에 전달할 수 있다. 이때 전달되는 인수를 명령라인 인수라고 한다.
101
명령라인 인수의 사용방법 명령라인 인수를 사용하기 위해서는 main ()함수의 인수가 void가 아닌 int형과 char형 포인트 배열을 사용한다.
102
DOS 창에서 프로그램 실행 명령라인 인수를 사용하기 위해서는 visual C++ 6.0에서 바로 실행되지 않고, DOS 창 등에서 실행 파일을 입력하여 실행시켜야 한다.
103
메모리에서 저장되는 형태 명령라인 인수의 구조
104
예제 9-15 명령라인 인수를 활용하여 화면에 개수와 문자열 출력하는 프로그램
명령라인 인수를 활용하여 DOS 창에서 실행 프로그램을 실행시켜 화면에 전체 인수의 개수와 각 인수별로 출력하는 프로그램을 작성한다.
105
예제 9-15 명령라인 인수를 활용하여 화면에 개수와 문자열 출력하는 프로그램
// C_EXAMPLE\ch9\ch9_project15\cmdlinearg.c #include <stdio.h> // 명령라인 인수 선언 void main(int argc, char* argv[]) { int i = 0; printf("argc = %d \n", argc); // 명령라인 인수의 개수 만큼 루프를 반복 while(i < argc) printf("argv[%d] = %s \n", i, argv[i]); i++; } // while } // main() 반드시 argc, argv라는 변수명을 쓰지 않아도 된다. 두 번째 인수는 포인터 배열이다. argc는 실행 파일 이름을 포함한 개수 각 문자열들의 첫 주소를 가지고 있음
106
예제 9-15 시작 메뉴에서 실행을 클릭한다
107
예제 9-15 실행 창에 “cmd”라고 입력한다
108
예제 9-15 DOS 창에서 현재 작성한 project의 경로로 진입한다.
109
예제 9-15 실행 파일을 실행시킨다.
110
예제 9-15 실행결과 확인 명령라인 인수의 개수 문자열 배열
Similar presentations