1 / 55

3 장 . 포인터 , 배열 , 구조체

3 장 . 포인터 , 배열 , 구조체. Internet Computing Laboratory @ KUT Youn-Hee Han. 1. 포인터. 포인터 변수 (Pointer Variable) int *p; Something pointed by p is of type integer 핸들 (Handle) 이라고도 한다 . 변수에는 주소 (Address) 값이 들어간다 . Dereference (Indirection) Operator: Asterisk, * 타입 변환 (Type Casting).

minna
Télécharger la présentation

3 장 . 포인터 , 배열 , 구조체

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. 3장. 포인터, 배열, 구조체 Internet Computing Laboratory @ KUT Youn-Hee Han

  2. 1. 포인터 • 포인터 변수 (Pointer Variable) • int *p; • Something pointed by p is of type integer • 핸들 (Handle)이라고도 한다. • 변수에는 주소 (Address) 값이 들어간다. • Dereference (Indirection) Operator: Asterisk, * • 타입 변환 (Type Casting) int *p; *p =15; int *p; p=(int *)malloc(sizeof(int)); *p =15; 주소 값 변수 int Date, Month; int *p; float *q;  Data Structure

  3. 1. 포인터 • 동적 변수공간 할당 • int *p; • p = (int *) malloc(sizeof(int)); • *p = 15; • *p는 힙 메모리 변수, p는 스택 메모리 변수 • 익명 변수 (Anonymous Variable) 주소 값 변수 Address 800 p 800 p=(int*)malloc(sizeof(int)); ??? *p=15; 800 15 Data Structure

  4. 1. 포인터 • 정적 메모리 할당 (Static Memory Allocation) • 동적 메모리 할당 (Dynamic Memory Allocation) Address 800 p 800 if (pi != NULL) { delete pi; } p=(int*)malloc(sizeof(int)); ??? 800 *p=15; 15 Year 800 free(p); 15 2003 Operating System Uses It Data Structure

  5. 1. 포인터 • 널 (Null) 포인터 • ‘현재 아무 것도 가리키지 않고 있다’는 의미 • free (p);             p가 가리키는 변수 공간을 반납 p = NULL;      p를 따라가지 않도록 • 접근 위반 (Access Violation) • free(p)에 의하여 p가 가리키는 변수공간은 운영체제에 반납되지만 포인터 변수 p의 자체 공간은 프로그램이 끝날 때까지 반납이 안됨. • 즉, free(p) 이후에도 p 안에는 800이라는 주소값이 그대로 존재 • 운영체제는 800 주소에 해당하는 메모리를 활용하여 Year라는 변수를 저장하기 위하여 사용 가능 • 변수 p 자체는 정적으로 할당된 변수임 • p의 값이 여전히 800이라고 해서 해당 포인터를 따라가서 그 값을 건드린다면 큰 문제 • # define SAFE_FREE ( a ) { free ( a ) ; a = NULL ; } Data Structure

  6. 1. 포인터 • LValue (Left Value) vs. RValue (Right Value) • ‘L’ in LValue can be thought of as “location”, meaning a variable has a location that data or information can be put into. • ‘R’ in RValue can be thought of as “read” value, meaning a data value of the variable, that is, what information it contains • int x; x = 5; // This is fine, 5 is an RValue, x can be an LValue. 5 = x; // This is illegal. A literal constant such as 5 cannot be a lvalue. • LValue is contrasted with a constant. A constant has some data value, that is an RValue. But, it does not have an LValue. • *p = 15; *p는 등식의 좌변 값(LValue)으로 사용가능 • data = *p; *p는 등식의 우변 값(RValue)으로도 사용가능 Data Structure

  7. 1. 포인터 • Address Operator: Ampersand, & • ‘Address of’ • 변수 Date의 주소 값을 포인터 변수 p에 할당 • 변수에 대한 두가지 접근방법: Date = 12; 또는 *p = 12; int Date, month; int *p; p = &Date; P=&Date; *P=12 Data Structure

  8. 1. 포인터 • *&Date = 15; • *(&Date)는 ‘변수 Date의 주소 값이 가리키는 것’ • 변수 Date의 주소 값이 가리키는 것은 변수 자체 • 변수를 주소 값으로 매핑(Mapping)시키는 함수가 앰퍼샌드(&) • 그 주소가 가리키는 값으로 매핑시키는 함수가 애스터리스크(*). • 역함수이므로 *&Date = Date와 동일한 의미 *(&Date) 주소 값 변수 200 15 Date &Date Data Structure

  9. 1. 포인터 • Generic Pointer • 포인터는 그것이 가리키는 변수의 타입에 따라 분류 • 가리키는 변수에 따라 읽어와야 할 데이터의 분량이 달라짐. • void *Ptr; 선언시에는 가리키는 대상을 명시하지 않음 • Ptr = (float *)malloc(sizeof(float)); • 타입변환 연산자에 의해 실행시 포인터의 타입을 할당 • float *Ptr; 로 선언되었다면 (float *)는 없어도 된다 • Code Readability 효과를 기대하기 위해 사용하는 것이 바람직 Data Structure

  10. 1. 포인터 • Dangling Pointer • int *p, *q; p = (int *) malloc(sizeof(int)); *p = 15; q = p; free (p); p = NULL; *q = 30; Data Structure

  11. 1. 포인터 • Garbage: 반납도 접근도 할 수 없는 공간 • int *p; *q; p = (int *)malloc(sizeof(int)); q = (int *)malloc(sizeof(int)); *p = 5; *q = 20; p = q; Data Structure

  12. 1. 포인터 • 상수변수 • int a = 24; const int* Ptr = &a; • 상수 포인터 • 포인터가 항상 일정한 메모리 주소를 가리킴 • int* const Ptr = new int; *Ptr = 25; • int a; *Ptr = &a; (이것은 오류) #include "stdafx.h" int main(int argc, char* argv[]) { int a = 24; const int* Ptr = &a; *Ptr = 30; // a = 30; return 0; } #include "stdafx.h" int main(int argc, char* argv[]) { int a = 24; int* const Ptr = new int; *Ptr = 30; Ptr = &a; return 0; } Data Structure

  13. 2. 참조 호출과 값 호출 • Call by Reference • Pass by Reference • 참조 호출 • Call by Value • Pass by Value • 값 호출 • Actual Parameter • Formal Parameter • 함수의 리턴 값은 ‘Pass by Value’를 따른다. Data Structure

  14. 2. 참조 호출과 값 호출 • Call by Value void fcn(int i) { i = 5; } void main( ) { int n = 3;   fcn(n);   printf("%d", n); } Data Structure

  15. 2. 참조 호출과 값 호출 • Return - Call by Value • 함수실행 결과 리턴 값 • 복사에 의해 전달 됨 • 호출함수에게 리턴 되는 것은 변수 b 가 아니고, 변수 b를 복사한 값 • 지역변수는 함수 실행 종료와 함께 그 수명이 끝남. • 호출함수로 되돌아 온 순간에는 더 이상 존재하지 않음 • 따라서 지역변수를 리턴 할 수는 없음 int fcn(int& a) { int b = a;   ...   return b; } Data Structure

  16. 2. 참조 호출과 값 호출 • Call by Reference void fcn(int *pi) { *pi = 5; } void main( ) { int n = 3; fcn(&n); printf(“%d”,n); } Data Structure

  17. 2. 참조 호출과 값 호출 • Pass by Value (by Copy Constructor – Shallow Copy) • Pass by Reference • 대용량 데이터: 참조호출에 의해 복사에 소요되는 시간을 줄임 void fcn(bookclass b) { cout << b.Number;    책의 일련번호를 프린트하기 }                         void main( ) { bookclass MyBook;    bookclass에 속하는 MyBook 객체선언 fcn(MyBook);     } void fcn(bookclass *b) { cout << (*b).Number;    책의 일련번호를 프린트하기 }                         void main( ) { bookclass MyBook;    bookclass에 속하는 MyBook 객체선언 fcn(&MyBook);     } Data Structure

  18. 2. 참조 호출과 값 호출 • Alias (&) • Address 연산자가 아님. • 에일리어스(Alias, Reference, 별명)을 의미 • 호출함수에서 던져준 변수 n을 ‘나로서는 일명 pi’로 부르겠다. • 참조호출의 효과(본명이나 별명이나 동일한 대상) • 왜 Alias를 사용하는가 • 포인터 기호 없이 간단하게 참조 호출 • 호출함수에서는 무심코 변수 자체를 전달 • 피호출 함수에서 에일리어스로 받으면 참조 호출, 그냥 받으면 값 호출 void fcn(int &pi) { pi = 5; } void main( ) { int n = 3;   fcn(n); cout << n; } Data Structure

  19. 2. 참조 호출과 값 호출 • Swapping Example void swap (int x, int y) { int temp;   temp = x; x = y; y = temp; } void main( ) { int a = 20;   int b = 40;   swap(a, b);   cout << a; cout << b; } void swap (int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; } void main( ) { int a = 20; int b = 40; swap(&a, &b); cout << a; cout << b; } void swap (int& x, int& y) { int temp;                       temp = x; x = y; y = temp; } void main( ) { int a = 20;   int b = 40; swap(a, b); cout << a; cout << b; } Data Structure

  20. 3. 배열 • 직접 접근 • 인덱스 계산에 의해 해당 요소의 위치를 바로 알 수 있음 • i 번째 요소의 주소 • &A[i-1] = &A[0] + (i - 1) * sizeof(Element Type) Data Structure

  21. 3. 배열 • 2차원 배열: 행 우선(Row-major Order) • 배열의 특성 • 크기가 고정된다. • char name[10]; • char name[200]; • 배열 변수 자체는 상수 포인터 • 허용된 배열 공간 바깥을 접근하는 것은 컴파일러가 걸러주지 못한다. char a = ‘k’; char name[3] = {‘k’, ‘I’, ‘m’} name = &a; //error! Data Structure

  22. 3. 배열 • 포인터 산술 연산 • 배열 인덱스와 포인터 산술 연산 Data Structure

  23. 3. 배열 • 배열 과 포인터 • 배열 이름은 배열의 시작주소 값을 지님. 즉 포인터에 해당 • 배열은 프로그램 시작 시에 메모리 위치가 고정 • 따라서 배열변수는 일종의 상수  포인터에 해당 #include <stdio.h> int main(void) { int a[5] = {10,20,30,40,50}; int b=60; int *c; printf("a[0]: %d, a[1]: %d, b: %d \n", a[0], a[1], b); c = a; printf("c[0]: %d, c[1]: %d, b: %d \n", c[0], c[1], b); printf("*c: %d, *(c+1): %d, b: %d \n", *c, *(c+1), b); //a = &b; return 0; } 주석 해제했을 때의 에러내용은? Data Structure

  24. 3. 배열 • 배열의 전달 • 배열변수 이름, 즉 포인터 값이 복사되어 넘어감. • Call by reference 효과 • 따라서 피 호출함수에서 작업을 가하면 이는 원본을 건드리는 참조호출 효과 int SumUp(int A[ ], size) { int Sum = 0; for (int i = 0; i < size; i++)Sum += A[i]; return Sum; } void main( ) { int Total; int Score[5];   Score[0] = 98; Score[1] = 92; Score[2] = 88; Total = SumUp(Score, 3); } Data Structure

  25. 3. 배열 • 배열의 전달 Data Structure

  26. 3. 배열 • 배열의 전달 • 포인터로 직접 받아서 처리도 가능 • 상수 배열 • 읽기를 위한 접근만 허용 – 배열의 내부 요소 변경 못함 • int SumUp(const int A[ ], size) • int SumUp(const int *A, size) int SumUp(int *A, size) { int Sum = 0;   for (int i = 0; i < size; i++) { Sum += *A;          ++A;   } return Sum; } void main( ) { int Total; int Score[5];   Score[0] = 98; Score[1] = 92; Score[2] = 88; Total = SumUp(Score, 3); } 하지만, A값 자체는 변경 가능 (ex. A++) Data Structure

  27. 3. 배열 • 정적배열과 동적배열 • 정적 배열은 스택에(변수 선언에 의함) • 동적배열은 힙에 (malloc, new 등 함수 실행에 의함) • 정적 배열 크기는 컴파일 시에, 동적 배열 크기는 실행 중에 결정 • 동적 배열도 실행 중에 그 크기를 늘릴 수는 없음 void Function1(int Size) { int MyArray[Size];                    정적 배열 선언 (컴파일 오류) ... } void Function2(int Size) { int *MyArrayPtr = new int[Size];    동적 배열 선언 ...   delete[ ] MyArrayPtr; } Data Structure

  28. 4. 구조체 • 필드, 레코드, 파일 필드 파일 레코드 Data Structure

  29. 4. 구조체 • 구조체 선언 및 사용 방법 • struct car { char Title[12]; int Year; int Price; }; • struct car MyCar; • typedef struct { char Title[12]; int Year; int Price; } carType • carType MyCar; • carType MyCar {"RedSportCar", 2005, 2000}; • carType CarArray[100]; typedef A B Ex.]typedef int* prtType;prtType p; Data Structure

  30. 4. 구조체 • 구조체와 포인터 • carType MyCar {"RedSportCar", 2005, 2000}; carType *p; p=&MyCar; • 주의점 • (*p).Year와 *p.Year는 다르다. • 연산자 우선순위에 의하여 . (dot) 연산자가 * (Asterisk) 연산자보다 우선 평가 • (*p).Year와 P->Year는 같다. Data Structure

  31. 4. 구조체 • 구조체내부에 포인터 변수 사용  개념적 재정의 • typedef struct { int *OwnerAge; int *CarPrice; } OwnerAndPriceType; OwnerAndPriceType P; P.OwnerAge = &Age; P.CarPrice = &Price • 복사본을 만들지 않음 • 원본을 그대로 유지 • 원본을 가리키는 포인터만 재 구성 • 원본이 바뀌면 자동으로 내용이 바뀜 Data Structure

  32. 4. 구조체 • 함수파라미터로 구조체 전달 • Pass by Value • 필드 단위의 복사 (Shallow Copy) • FunctionCall(carType ThisCar) { ... } main( ) { carType MyCar; FunctionCall(MyCar); } • Pass by Reference 가능 • 호출함수: FunctionCall(&MyCar); • 피 호출함수: FunctionCall (carType *ThisCar) Data Structure

  33. 5. 활성화 레코드 (Activation Record) • 프로그램 수행시 메모리의 구성 (시스템 마다 틀림) • An Activation Record corresponds to a call to a function which has not yet terminated with a return. Data Structure

  34. 5. 활성화 레코드 (Activation Record) • 메인함수 호출에 따른 활성화 레코드 • int a;                  전역 변수 void main( ) { int b; char *s;       지역변수(스택) s = malloc(10);      10 바이트짜리 동적변수(힙) b = fcn(5); free (s); } Data Structure

  35. 5. 활성화 레코드 (Activation Record) • 일반 함수 호출에 따른 활성화 레코드 • int fcn(int p)  {  파라미터(스택) int b = 2;     b = b + p; return (b); } Data Structure

  36. 5. 활성화 레코드 (Activation Record) • Context Switching • 새로운 함수호출은 Context Switching 수반 • 새로운 활성화 레코드 생성 • 연속적인 함수호출에 따라 활성화 레코드 스택이 생성 • 함수 종료시 제일 위의 활성화 레코드가 사라짐으로써 직전의 상황을 복원 • Stack Overflow • 무한 루프내에서 함수 호출을 계속할 때 • 재귀적 호출에서 빠져나오지 못할 때 • Heap Overflow? • 무한 루프내에서 동적 메모리 할당 (new int)를 계속 할 때 • 더 이상 할당할 힙 공간이 없을 때 NULL 을 반환 • 힙 메모리 소진을 대비한 코드int *ptr = new int; if (ptr == NULL) ….. Data Structure

  37. 6. 디버깅을 위한 매크로 • 디버깅을 위한 코드 #include <assert.h> float SquareRoot (float t) { assert (t >= 0); return sqrt(t); } • 디버깅이 완벽히 수행된 이후 완성 코드 #define NDEBUG #include <assert.h> float SquareRoot (float t) { assert (t >= 0); return sqrt(t); } Conditional Macro Data Structure

  38. Homework • 3장 연습문제 (pp.122~130) • 문제 2: 풀이 과정 설명 포함 • 문제 9: 문제를 먼저 풀고 프로그램 작성하여 확인 • 문제 25: 출력 내용 및 이유 설명 • 문제 27: 출력 내용 및 이유 설명 • 문제 34: 구체적 설명 제시 • 문제 48: 수행가능한 완벽 소스 코드 - Average 함수 내에서 b 에 대하여 NULL 값이 들어오는 지 체크하는 assert 매크로 활용하는 내용 포함 • 가능한한 모든 문제에 대하여 코드 작성하고 수행 모습 캡쳐!!! • 제출 메일의 제목 [철저하게 지킬것!] • 자료구조-2차-이름-학번 • 기한 • 4월 10일 23시 59분 59초 Data Structure

  39. Appendix Data Structure

  40. 1. 프로세스의 메모리 배치 • 프로세스 이미지 • 프로세스는 일정한 메모리를 배정 받아 사용 • 프로그램 실행에 필요한 어셈블러 코드, 변수가 저장 • 원칙적으로 한 프로세스는 다른 프로세스의 메모리 영역에 접근 불가 • C 프로그램과 이미지의 내용 #include <stdio.h> #include <stdlib.h> extern char **environ; //extern 변수 int init_global_var = 3; //초기화된 global 변수 int unint_global_var; //초기화되지 않은 global 변수 int main(int argc, char **argv) { int auto_var; //automatic 변수 (local variable) static int static_var; //static 변수 register int reg_var; //register 변수 char *auto_ptr; //automatic 변수 (local variable) auto_ptr = malloc(10); return 0; } Data Structure

  41. 1. 프로세스의 메모리 배치 • 프로세스의 메모리 영역과 저장되는 변수 종류 하위 메모리 상위 메모리 Data Structure

  42. 1. 프로세스의 메모리 배치 • 참고: http://kucg.korea.ac.kr/~sjkim/teach/2001/cse037/l04.html #include <stdio.h> void test(void) { static int s_count=0; int a_count=0; s_count++; a_count++; printf("static count=%d\tauto count=%d\n", s_count, a_count); } void main(void) { int i; for(i=0; i<5; i++) test(); } http://myhome.hanafos.com/~kukdas/doc/c_lect/c_lect-7.html Data Structure

  43. 2. 스택과 힙 • 스택 (Stack) • 현재 호출되어 실행중인 함수의 코드와 환경 정보를 저장 • 예) • main()에서 printf()를 호출하였다면 main()이 차지하는 영역 위에 printf()를 처리하기 위한 메모리가 할당되고 printf()가 수행 • print()가 리턴되면 printf()와 관련된 영역은 삭제되고 프로세서의 수행은 main()으로 돌아감 • 함수 내부에서 임시로 사용되는 automatic 변수는 스택 영역에 할당 • automatic 변수 – 자동으로 생성되었다가 자동으로 없어지는 변수 • 힙 (Heap) • 스택은 영역 사용하던 메모리가 함수의 종료와 함께 사라짐 • 이 문제를 해결하기 위하여 리턴되어도 사라지지 않도록 한 영역이 힙 • malloc() 함수를 사용한 역영은 힙에 저장 Data Structure

  44. 2. 스택과 힙 int main() { char *prt; ptr = func(); } char *func() { char arr[10]; return arr; } int main() { char *prt; ptr = func(); // ptr 사용 free(ptr); // ptr 사용 종료 } char *func() { char *arr; arr = malloc(10); return arr; } Data Structure

  45. 3. 참조 호출과 값 호출 • A copy constructor • is a constructor that takes as an argument the type of itself, e.g. molecule::molecule(molecule &x) • complex c1; // normal constructor called • complex c2 = c1; // copy constructor needed • This is a special case only because a default copy constructor is provided by the compiler • if you don’t write one, the default simply does a shallow copy of the object (copies pointers) Data Structure

  46. 3. 참조 호출과 값 호출 • Copy Constructor • A copy constructor is called whenever a new variable is created from an object. This happens in the following cases (but not in assignment). • A variable is declared which is initialized from another object, eg, • Point q("Mickey"); // Normal constructor is used to build q. • Point r(q); // copy constructor is used to build r. • Point p = q; // copy constructor is used to initialize in declaration. • p = q; // Assignment operator, no copy constructor. • At function call, a parameter is initialized from its corresponding argument. • f(p); // copy constructor initializes formal value parameter. • An object is returned by a function. • If there is no copy constructor defined for the class, C++ uses the default copy constructor which copies each field, ie, makes a shallow copy (member-wise copy). • 프로그래머가 직접 관리하는 사용자 복사 생성자를 사용하는 것이 좋음. Data Structure

  47. 3. 참조 호출과 값 호출 • Copy Constructor Syntax //=== file Point.h ============================================= class Point { public: . . . Point(const Point& p); // copy constructor . . . //=== file Point.cpp ========================================== . . . Point::Point(const Point& p) { x = p.x; y = p.y; } . . . //=== file my_program.cpp ==================================== . . . Point p; // calls default constructor Point s = p; // calls copy constructor. p = s; // assignment, not copy constructor. Data Structure

  48. 3. 참조 호출과 값 호출 • Deep Copy vs. Shallow Copy • 프로그래머가 직접 복사 생성자를 코딩하여 Deep Copy 방법을 구현 Data Structure

  49. 3. 참조 호출과 값 호출 • Deep Copy vs. Shallow Copy: Example class atom { private: int x, y, z; public: x(); y(); z(); }; class molecule { private: int n; atom *atom_array; public: // constructor molecule(int natoms); }; molecule::molecule(int natoms){ n = natoms; atom_array = new atom[natoms]; } Data Structure

  50. 3. 참조 호출과 값 호출 • Deep Copy vs. Shallow Copy: Example Shallow Copy! Data Structure

More Related