1 / 43

상수 /inline/ 포인터의 이해 C++ 언어 4 일차 강 성 관

상수 /inline/ 포인터의 이해 C++ 언어 4 일차 강 성 관. 상수 (const) 값과 상수 변수. define 을 이용 , const 키워드를 이용해서 변수를 이용 define 문은 상수 뿐 아니라 코드를 바로 정의해서 둘 다 사용 가능 . 데이터형을 가질 수 없다 . (1) 값을 정의한 경우 #define MAX_SIZE 255 (2) 코드를 정의한 경우 #define MAX(a,b) a>b ? a:b

Download Presentation

상수 /inline/ 포인터의 이해 C++ 언어 4 일차 강 성 관

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 상수/inline/포인터의 이해C++ 언어 4일차강 성

  2. 상수(const)값과 상수 변수 • define을 이용 , const 키워드를 이용해서 변수를 이용 • define 문은 상수 뿐 아니라 코드를 바로 정의해서 둘 다 사용 가능. • 데이터형을 가질 수 없다. • (1) 값을 정의한 경우#define MAX_SIZE 255 (2) 코드를 정의한 경우 #define MAX(a,b) a>b ? a:b • C++ 에서는 주로 #define 문을 이용하기 보다 const를 이용해서 상수를 정의. • const는 선언에서 초기화 해야 한다. • const 데이터형 상수이름 = 값 ; • 상수도 변수와 같이 메모리에 값을 저장할 위치를 가지고 있고 데이 터형도 가진다. 단, 값을 바꿀 수는 없다. • 예) const short int MAX_SIZE = 255

  3. 확장함수(inline function) • 기능 • 일반 함수와 같이 분기하여 실행한 후, 복귀하는 과정 없이 직접 실행함으로 일반함수에 비해 실행속도가 빠르다. • 단점 • 함수의 내용이 복사되므로 소스 코드의 길이가 길어진다. • Format inline 반환형 함수명(인수 리스트) { ………………. }

  4. 인라인 함수(2) • 인라인(in-line) 함수란? - C에서 매개변수를 갖는 매크로(macro) 함수의 작동방식과 같음 - 함수호출 대신에, 호출될 함수를 그 라인에 삽입한다. - 예제 #include<iostream.h> inline int even(int x) { return !(x%2); } main() { int i=10; if(even(i)) //if (!(i%2))와 동일 cout << i << “is even \n”; else cout << i <<“is odd \n”; return 0; }

  5. 인라인 함수(3) • 인라인 함수(또는 매크로 함수)의 장단점 - 장점 : 함수를 호출하고 값을 반환하는데 드는 overhead가 없음 - 단점 : 자주 호출될수록 프로그램이 커짐 • 매크로와 비교할 때, 인라인 함수의 장점 - 부수적인 괄호삽입 문제점 해결 - 컴파일러에 의해 더 최적화됨 • 다음의 경우에 인라인 함수는 보통함수처럼 컴파일됨 - e.g.) static 변수, 반복문, switch문 또는 goto문 사용

  6. 자동 인라인(1) • 자동 인라인(in-line) 함수란? - 클래스 안에서 정의(구현)된 함수 - 예제 #include<iostream.h> class samp { int i,j; public: samp(int a, int b) // 자동 인라인 함수 { i = a; j = b; } int divisible(); };  뒤에 계속

  7. 자동 인라인(2) inline int samp :: divisible() // 인라인 함수 { return !(i%j); } main() { samp ob1(10,2), ob2(10,3); if(ob1.divisible()) cout << “10 divisible by 2 \n”; if(ob2.divisible()) cout << “10 divisible by 3 \n”; return 0; } • 자동 인라인 함수의 전형적인 사용 • - 생성자 함수와 소멸자 함수 • - 작은 크기의 함수

  8. 포인터란 무엇인가? • 포인터와 포인터 변수 • 메모리의 주소 값을 저장하기 위한 변수 • "포인터"를 흔히 "포인터 변수"라 한다. • 주소 값과 포인터는 다른 것이다. int main(void) { char c='a'; int n=7; double d=3.14; . . . . . 그림 1

  9. 포인터의 개념 char *p; char q = ‘A’; p = &q; : : 1000 p 1001 p는 char타입의 문자형 변수 q의 메모리 주소를 참조하는 문자형 포인터 변수 1002 포인터 변수 p는 문자형 변수 q를 가리킨다. A 1005 1003 1004 q 1005 1006 1007 :

  10. 포인터란 무엇인가? • 그림을 통한 포인터의 이해 • 컴퓨터의 주소 체계에 따라 크기가 결정 • 32비트 시스템 기반 : 4 바이트 그림 2

  11. 포인터란 무엇인가? • 포인터의 타입과 선언 • 포인터 선언 시 사용되는 연산자 : * • A형 포인터(A*) : A형 변수의 주소 값을 저장 int main(void) { int *a;// a라는 이름의 int형 포인터 char *b;// b라는 이름의 char형 포인터 double *c;// c라는 이름의 double형 포인터 . . . . .

  12. 포인터란 무엇인가? • 주소 관련 연산자 • & 연산자 : 변수의 주소 값 반환 • * 연산자 : 포인터가 가리키는 메모리 참조 int main(void) { int a=2005; int *pA=&a; cout<<“a=“<<a ; //직접 접근 cout<<“*pA=” <<*pA ; //간접 접근 . . . . . 그림 3

  13. 포인터란 무엇인가? • 포인터에 다양한 타입이 존재하는 이유 • 포인터 타입은 참조할 메모리의 크기 정보를 제공 #include <iostream> using namespace std ;  int main(void) { int a=10; int *pA = &a;  double e=3.14; double *pE=&e; cout<<“*pA=“<< *pA<<“,”<< “*pE= “<<*pE <<endl ; return 0; }

  14. 잘못된 포인터의 사용 • 사례 1 • 사례 2 int main(void) { int *pA; // pA는 쓰레기 값으로 초기화 됨 *pA=10; return 0; } int main(void) { int* pA=100; // 100이 어딘 줄 알고??? *pA=10; return 0; }

  15. 포인터의 데이터 형 • 포인터 변수가 가리키는 대상체의 자료 형

  16. 주의 • 포인터 변수를 이용한 대상체의 값 변경 • 포인터 변수 명 앞에 * 을 붙인 다음 값을 할당한다. • lvalue로사용된 *pc 는변수명처럼사용된다. • pc가 가리키는 주소의 값을 ’B’로 변경한다.

  17. 포인터 초기화 • 포인터 변수 역시 사용 전에 반드시 선언되어야 한다. • 선언된 포인터 변수는 반드시 초기화 되어야 한다. • 포인터를 이용하려면 메모리 위치가 필요하므로 • 초기화 방법 int value ; int* pvalue1 = &value ;//&연산자를 이용해서 주소값 구하기 int* pvalue2 = 0 ; //포인터 변수 선언과 동시에 0값의 주소로 초기화 pvalue1 = pvalue2 ; //pvalue2를 pvalue1 에 할당

  18. 포인터 변수의 참조 예 #include<iostream> using namespace std void main() { int *p, k=3, j ; p = &k ; /* 포인터 변수 p는 k의 주소를 가리킴 */ j = *p ; /* 포인터 변수 p가 가리키는 주소의 내용을 변수 j 에 대입 */ j++ ; /* 변수 j의 값을 1증가 */ cout<<"*p =“ << *p <<endl ; cout<<"p가 저장하고 있는 주소값= “ <<p ; cout<< " j = “ << j <<endl ; } 변수 j • 포인터 변수의 참조를 기억 공간 표현으로 나타내면 변수 k 3 -> 4 3 0x0012FF78 0x0012FF78 포인터 변수 p

  19. 포인터 연산과 기억 공간의 표현(1) • 포인터값에 정수값을 더하거나 빼서 메모리 주소를 계산할 수 있음. • 포인터와 포인터를 비교 가능 예) short int *pbase ; pbase++ ; //pbase = pbase + 1 pbase-- ; //pbase = pbase – 1 pbase +=2 ; //pbase = pbase +2 pbase -= 2 ; //pbase = pbase – 2 pbase1 = pbase + 10 ; • 배열과 포인터에서 값과 주소를 가져오는 방법 • 값을 가져올 때 array[0] array[1] array[2] *pbase *(pbase + 1) *(pbase+2) • 주소를 가져올 때 &array[0] &array[1] &array[2] pbase pbase + 1 pbase + 2

  20. 포인터 연산과 기억 공간의 표현(2) <int *p ; 의 경우 > <char *p ; 의 경우 > p = 100 일 때 p = 100 일 때 주소 <기억 공간> <포인터> 주소 <기억공간> <포인터> <- p <- p+1 <- p+2 <- p+3 100-> 101-> 102-> 103-> *p *(p+1) *(p+2) *(p+3) ... <- p <- p+1 <- p+2 <- p+3 100-> 104-> 108-> 112-> *p *(p+1) *(p+2) *(p+3) ... 포인터를 1 증가시키면 실제 주소 포인터를 1 증가시키면 실제 주소 (주소)는 int 의 경우 4 byte 증가 (주소)는 char의 경우 1 byte 증가

  21. 포인터연산과 기억 공간의 표현(3) • p가 포인터 경우 p를 1 증가시키면 실제 증가되는 주소(번지)는 *p 의 자료형의 바이트 수가 된다. (예) p = 100 이라면 int *p 일 때 (p+3) 의 번지는 100 + 3 * 4 번지 char *p 일 때 (p+3) 의 번지는 100 + 3 * 1 번지float *p 일 때 (p+3) 의 번지는 100 + 3 * 4 번지 • 포인터의 실제값(주소)은 자료형의 크기 단위로 증가 또는 감소할 수 있기 때문에 결과적으로 *(p+i) 는 기억 공간 중에서 해당 주소의 자료를 액세스할 수 있음을 의미한다.

  22. 포인터 이용 • 문자열과 char형 포인터 • char형 포인터변수는 주로 문자열을 가리킵니다. • 문자열은 메모리에 연속된 문자가 나열된 것으로써 ‘\0‘문자(null 문자)로 끝난다. • 문자열의 시작은 char형 포인터로 가리키게 됩니다. • 문자열은 포인터가 가리키는 위치부터 ‘\0‘문자가 나올 때 까지 나오는 모든 문자를 하나의 문자열로 인식합니다. • char 형은 1 Byte 이므로 알파벳 하나는 1Byte

  23. 포인터와 배열의 관계 • 배열 이름과 포인터 비교 int main(void) { int a[5]={0, 1, 2, 3, 4}; int b=10; a=&b; //a는 상수이므로 오류, a가 변수였다면 OK! }

  24. 포인터와 배열의 관계 • 배열 이름의 타입 • 배열 이름도 포인터이므로 타입이 존재 • 배열 이름이 가리키는 배열 요소에 의해 결정 int arr1[10] int* double arr2[20] double*

  25. 포인터와 배열의 관계 • 배열 이름의 활용 • 배열 이름을 포인터처럼, 포인터를 배열 이름처럼 활용하는 것이 가능! /* pointer_array2.cpp */ #include <iostream>  using namespace std ; int main(void) { int arr[3]={0, 1, 2}; int *ptr;  ptr=arr; cout<< ptr[0]<<ptr[1] <<ptr[2]<<endl ; return 0; } 그림 4

  26. p+1 p+2 p l H \0 o l e 배열과 포인터 (1/10) 1차원 배열과 포인터 • 배열명은 포인터 상수다! 그 값을 변경할 수 없다. • 별도의 포인터 변수에 배열의 시작주소를 담을 수 있다. a[0] a[1] a[2] a[3] a[4] a[5] char a[6] = “Hello”; char *p, *p2; p = a; p2 = &a[3]; 배열명 a p+3 p+4 p+5 a[n] 과 *(a + n) 또는 *(p + n)은 완전히 동등한 수식이다. 포인터 p2+1 p2+2 p2 포인터

  27. 배열과 포인터 (2/10) • 1차원 배열과 포인터와의 관계

  28. Step1. Step2. 배열과 포인터 (3/10) • 1차원 배열을 포인터 수식으로 쉽게 바꾸기 배열 기호 []를 생략하고 배열 명 a앞으로 빼내면서 *로 바꾼다. *뒤에 남은 요소를 (배열명 + 첨자) 형태로 바꾼다.

  29. p+1 p+5 p+3 p+4 p+2 p a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 60 50 20 30 10 40 a 배열명 1000 1004 1008 1012 1016 1020 a[0] 배열명 a[1] 포인터 배열명 배열과 포인터 (4/10) 2차원 배열과 포인터 • 포인터 수식이 1차원 배열에 비해 복잡 • 포인터 수식이 여러 가지 의미로 해석되고 참조될 수 있으므로 주의가 필요 int a[2][3] = {10,20,30,40,50,60}; int *p; p = a; a[i][j] 는 *(*(a+i)+j) 와 동등한 표현이다.

  30. Step1. Step2. Step3. 배열과 포인터 (5/10) • 다차원 배열을 포인터 수식으로 쉽게 바꾸기 a[1][2]의 1차원 배열 기호 []를 생략하고 배열 명 a앞으로 빼내면서 *로 바꾼다. *뒤에 남은 요소를 (배열명 + 1차원첨자) 형태로 바꾼다. a[1]은 배열의 요소가 아니라 배열 명이다. a[1] == &a[1][0] == 0x1012 결국, a[1]+2 는 0x1012에서 2만큼 떨어진 0x1020을 의미하고 그 곳의 값은 60이다. 단계1~2를 a[1]에 반복 적용한다. 배열 명 a[1]을 의미, a에서 1만큼 떨어진 곳의 값이 아니다!!

  31. 배열과 포인터 (6/10)

  32. 배열과 포인터 (7/10) 배열 포인터 • 2차원 이상의 다차원 배열을 가리키는 포인터 • 배열 포인터를 선언 • p는 요소의 개수가 3개인 1차원 배열 2개를 가진 배열 a를 가리킴 • p == a[0] • p+1 == a[1]

  33. p a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 배열명 a 1000 1004 1008 1012 1016 1020 60 30 20 10 50 40 p+1 배열포인터 배열 포인터 p의 증가는 p가 가리키는 대상체인 2차원 배열의 1차원 요소 수만큼 증가한다. 배열과 포인터 (8/10) • 배열 포인터 int a[2][3] = {10,20,30,40,50,60}; int (*p)[3]; p = a; 1차원 배열의 요소 수 sizeof(p) = ? sizeof(p+1) = ? sizeof(*p) = ? sizeof(*(p+1)) = ?

  34. 주의 배열과 포인터 (9/10) sizeof(*(p+1))의 크기는 2*3*sizeof(int) == 24bytes 배열 포인터 p가 가리키는 대상체는 표면적으로 3차원 배열이지만 내부적으로 증가하는 단위는 배열 포인터 선언 시에 명시해준 2차원 배열의 크기만큼 증가한다.

  35. a a[0] a[0][0] p a[0][0][0] 1000 p+1 a[0][0][1] 1004 p+2 a[0][0][2] 1008 a[0][1] p+3 a[0][1][0] 1012 p+4 a[0][1][1] 1016 p+5 a[0][1][2] 1020 a[1] a[1][0] p+6 a[1][0][0] 1024 p+7 a[1][0][1] 1028 p+8 a[1][0][2] 1032 a[1][1] p+9 a[1][1][0] 1036 p+10 a[1][1][1] 1040 p+11 a[1][1][2] 1044 배열과 포인터 (10/10) 3차원 배열과 포인터 int a[2][2][3]; int *p = a; ⊙ 3차원 배열명 : a ⊙ 2차원 배열명 : a[0], a[1] ⊙ 1차원 배열명 : a[0][0], a[0][1], a[1][0], a[1][1] a[i][j][k] == *(*(*(a + i) + j) + k) *(a + i) : a[0], a[1] *(*(a+i)+j) : a[0][0], a[0][1], a[1][0], a[1][1] a[0][0][0] == *a[0][0] == **a[0] == ***a a == a[0] == a[0][0] == &a[0][0][0] == 0x1000 a[1] == a[1][0] == &a[1][0][0] == 0x1012 1, 2차원 배열을 가리키는 포인터 상수

  36. 문자열과 포인터(1/2) 문자열과 포인터

  37. str1 p는 원래 str1의 메모리 주소 0x1000을 가리키고 있었다. 1000 1001 1002 1003 1004 1005 X W H e o l r p+0 p+1 p+2 p+3 p+4 p+5 p str2 l l ! d o 2000 \0 \0 2000 2001 2002 2003 2004 2005 2006 str1, str2 : 배열 명 p : 포인터 변수 p+5 p+6 p+0 p+1 p+2 p+3 p+4 문자열과 포인터(2/2) • 문자열 포인터 변수

  38. 포인터 배열 (1/3) • 포인터 변수를 여러 개 모아 놓은 배열 포인터 배열 • 아래 두 문장의 차이는?

  39. 1500 10 1700 10 1702 10 2410 10 2622 10 포인터 배열 (2/3) ip 포인터 변수가 여러 개 필요하고 자주 참조된다면 포인터 변수를 일일이 선언하기 보다는 포인터 배열을 만들어 활용한다. 3000 3004 3008 3012 3016 ip[0] ip[1] ip[2] ip[3] ip[4] 1500 1700 1702 2410 2622 V3 v1 V2 V4 V5 NOTE배열 포인터와 혼동하지 말아야 한다. 배열 포인터는 배열을 가리키는 하나의 포인터 변수일 뿐이다. 그런 반면 포인터 배열은 다수의 포인터를 담아두기 위해 하나 이상의 메모리 공간을 할당 받은 배열이다. 다음과 같이 배열포인터와 포인터배열의 선언형태를 잘 구분할 수 있어야 하겠다. int (*p)[5]; /* 배열 포인터의 선언: p는 4바이트 포인터 변수, p가 가리키는 대상체는 5개의 요소를 가진 배열*/ int *p[5]; /* 포인터 배열의 선언: p는 20바이트 포인터 배열, 최대 5개의 포인터를 담을 수 있다. */

  40. 문자열 포인터 배열의 선언 char *menu[] = { “New Game”, “Load Game”, “2 Play”, “Option”, “Exit” }; e w G a m 2 e L o a d G a m e \0 menu[2] menu[3] \0 N menu[1] a menu[4] y \0 O p t P o i \0 E x i t \0 menu[0] l n menu[][10] 과 같이 일반 배열로 선언했을 때와의 차이를 알아야 한다. 메모리 용량 : 38 bytes 꼭 필요한 메모리 공간 만큼만 할당 받아 사용하게 된다. menu[5][10]으로 선언한 경우에 비해 메모리 낭비가 없다. 포인터배열 menu[4][2] 또는 *(*(menu+4)+2) 포인터 배열 (3/3)

  41. 1000 FA00 FFE0 FA00 FFE0 A p2 = &p1 p1 = &ch p2 p1 ch 다중 간접 참조 (1/3) • 포인터가 또 다른 포인터를 가리킴 – 포인터의 포인터 다중 간접 참조 char *p1, **p2, ch; p1 = &ch; p2 = &p1; **p2 = ‘A’; • 다중 간접 포인터(2중 포인터)

  42. 1000 FEC8 FA00 FFE0 FA00 FFE0 100 FEC8 p3 = &p2 p2 = &p1 p1 = &i p3 p2 p1 i ***p3 == **p2 == *p1 == i == 100 다중 간접 참조 (2/3) • 다중 간접 포인터(3중 포인터)

  43. 포인터배열 명령행 인자 FFE8 3000 argv[2] 3000 b.txt FFE4 argv[1] 2000 FFE0 2000 argv[0] 1000 a.txt main()의 매개변수 1000 FFE0 argv myview • argv : 명령행 인자 목록을 가진 포인터 배열을 가리키는 이중 포인터 다중 간접 참조 (3/3) • main()함수의 명령 행 인자 배열 argv

More Related