Presentation is loading. Please wait.

Presentation is loading. Please wait.

C++ Espresso 제3장 배열과 포인터.

Similar presentations


Presentation on theme: "C++ Espresso 제3장 배열과 포인터."— Presentation transcript:

1 C++ Espresso 제3장 배열과 포인터

2 이번 장에서 학습할 내용 배열의 개념 배열의 선언과 초기화 포인터의 개념 참조에 의한 호출 참조자의 개념 문자열의 개념
배열과 포인터에 대하여 학습합니다. 배열의 개념 배열의 선언과 초기화 포인터의 개념 참조에 의한 호출 참조자의 개념 문자열의 개념

3 배열이란? 배열(array): 같은 종류의 데이터들이 순차적으로 저장되어 있는 자료 구조

4 배열 원소와 인덱스 인덱스(index): 배열 원소의 번호 int grade[10]; 첨자 또는 인덱스

5 배열의 선언 자료형: 배열 원소들이 int형라는 것을 의미 배열 이름: 배열을 사용할 때 사용하는 이름이 grade
배열 크기: 배열 원소의 개수가 10개 인덱스(배열 번호)는 항상 0부터 시작한다. int score[60];             // 60개의 int형 값을 가지는 배열 grade float cost[12];           // 12개의 float형 값을 가지는 배열 cost char name[50];             // 50개의 char형 값을 가지는 배열 name char src[10], dst[10];   // 2개의 문자형 배열을 동시에 선언 int index, days[7];       // 일반 변수와 배열을 동시에 선언

6 배열 원소 접근 인덱스 grade[5] = 80; grade[1] = grade[0];
grade[i] = 100;           // i는 정수 변수 grade[i+2] = 100;         // 수식이 인덱스가 된다. grade[index[3]] = 100;   // index[]는 정수 배열

7 배열의 초기화

8 초기값이 부족한 경우

9 배열의 초기화 배열의 크기가 주어지지 않으면 자동적으로 초기값의 개수만큼이 배열의 크기로 잡힌다.

10 예제 #include <iostream> using namespace std; int main(void) {
const int STUDENTS=5; int grade[STUDENTS]; int sum = 0; int i, average; for(i = 0; i < STUDENTS; i++) cout << "학생들의 성적을 입력하시오: "; cin >> grade[i]; } sum += grade[i]; average = sum / STUDENTS; cout << "성적 평균= " << average << endl; return 0; 학생들의 성적을 입력하시오: 10 학생들의 성적을 입력하시오: 20 학생들의 성적을 입력하시오: 30 학생들의 성적을 입력하시오: 40 학생들의 성적을 입력하시오: 50 성적 평균 = 30

11 동적 배열 C++에는 더 좋은 배열이 존재한다. STL 라이브러리로 제공 벡터(vector)

12 중간 점검 문제 1. n개의 원소를 가지는 배열의 경우, 첫 번째 원소의 번호는 무엇인가?
3. 범위를 벗어나는 인덱스를 사용하면 어떻게 되는가? 즉 int a[10];과 같이 선언된 배열이 있는 경우, a[10]에 6을 대입하면 어떻게 되는가? 4. 배열 a[6]의 원소를 1, 2, 3, 4, 5, 6으로 초기화하는 문장을 작성하라. 5. 배열의 초기화에서 초기값이 개수가 배열 원소의 개수보다 적은 경우에는 어떻게 되는가? 또 반대로 많은 경우에는 어떻게 되는가? 6. 배열의 크기를 주지 않고 초기값의 개수로 배열의 크기를 결정할 수 있는가?

13 2,3,…, n차원 배열 int s[10]; // 1차원 배열 int s[3][10]; // 2차원 배열

14 2차원 배열의 초기화 int s[ ][5] = { { 0, 1, 2, 3, 4 }, // 첫 번째 행의 원소들의 초기값
  {  0,  1,  2,  3,  4 }, // 첫 번째 행의 원소들의 초기값   { 10, 11, 12, 13, 14 }, // 두 번째 행의 원소들의 초기값   { 20, 21, 22, 23, 24 }, // 세 번째 행의 원소들의 초기값 };

15 다차원 배열을 이용한 행렬의 표현 #include <iostream> 3 3 0
using namespace std; const int ROWS=3; const int COLS=3; int main() { int A[ROWS][COLS] = { { 2,3,0 }, { 8,9,1 }, { 7,0,5 } }; int B[ROWS][COLS] = { { 1,0,0 }, { 1,0,0 }, { 1,0,0 } }; int C[ROWS][COLS]; int r,c; for(r = 0;r < ROWS; r++) for(c = 0;c < COLS; c++) C[r][c] = A[r][c] + B[r][c]; cout << C[r][c] << " "; cout << endl; } return 0; 3 3 0 9 9 1 8 0 5

16 3차원 배열 #include <iostream> using namespace std; int main() {
int s[3][3][3]; // 3차원 배열 선언 int x, y, z; // 3개의 인덱스 변수 int i = 1; // 배열 원소에 저장되는 값 for(z=0;z<3;z++) for(y=0;y<3;y++) for(x=0;x<3;x++) s[z][y][x] = i++; return 0; }

17 정렬이란? 정렬은 물건을 크기순으로 오름차순이나 내림차순으로 나열하는 것
정렬은 컴퓨터 공학분야에서 가장 기본적이고 중요한 알고리즘중의 하나 정렬은 자료 탐색에 있어서 필수적이다. (예) 만약 사전에서 단어들이 정렬이 안되어 있다면?

18 선택정렬(selection sort) 선택정렬(selection sort): 정렬이 안된 숫자들중에서 최소값을 선택하여 배열의 첫번째 요소와 교환

19 선택 정렬 1/2 #include <iostream> using namespace std;
const int SIZE=10; void selection_sort(int list[], int n); void print_list(int list[], int n); int main() { int grade[SIZE] = { 3, 2, 9, 7, 1, 4, 8, 0, 6, 5 }; // 원래의 배열 출력 cout << "원래의 배열" << endl; print_list(grade, SIZE); selection_sort(grade, SIZE); // 정렬된 배열 출력 cout << "정렬된 배열" << endl; return 0; }

20 선택 정렬 2/2 void print_list(int list[], int n) { int i;
for(i = 0;i < n; i++) cout << list[i]; cout << "\n”; } void selection_sort(int list[], int n) int i, j, temp, least; for(i = 0; i < n-1; i++) least = i; for(j = i + 1; j < n; j++) // 최소값 탐색 if(list[j] < list[least]) least = j; // i번째 원소와 least 위치의 원소를 교환 temp = list[i]; list[i] = list[least]; list[least] = temp; 원래의 배열 정렬된 배열

21 이진 탐색 이진 탐색(binary search): 정렬된 배열의 중앙에 위치한 원소와 비교 되풀이

22 이진 탐색 int binary_search(int list[], int n, int key) {
        int low, high, middle;   low = 0;         high = n-1;   while( low <= high ){       // 아직 숫자들이 남아있으면                 middle = (low + high)/2;    // 중간 요소 결정                 if( key == list[middle] )  // 일치하면 탐색 성공                         return middle;                 else if( key > list[middle] )// 중간 원소보다 크다면                         low = middle + 1;    // 새로운 값으로 low 설정                 else                         high = middle - 1;   // 새로운 값으로 high 설정         }           return -1; }

23 포인터란? 포인터(pointer): 주소를 가지고 있는 변수

24 포인터의 선언 포인터: 변수의 주소를 가지고 있는 변수 int i = 10; // 정수형 변수 i 선언
int *p = &i; // 변수 i의 주소가 포인터 p로 대입

25 간접 참조 연산자 간접 참조 연산자 *: 포인터가 가리키는 값을 가져오는 연산자 int i = 10; int *p = &i;
cout << *p; // 10이 출력된다. *p = 20; cout << *p; // 20이 출력된다.

26 포인터의 증가는 일반 변수와는 약간 다릅니다. 가리키는 객체의 크기만큼 증가합니다.
포인터 연산 가능한 연산: 증가, 감소, 덧셈, 뺄셈 연산 증가 연산의 경우 증가되는 값은 포인터가 가리키는 객체의 크기 포인터 타입 ++연산후 증가되는값 char 1 short 2 int 4 float double 8 포인터의 증가는 일반 변수와는 약간 다릅니다. 가리키는 객체의 크기만큼 증가합니다.

27 증가 연산 예제 16진수 증가 전 pc = 00002710 pi = 00002710 pd = 00002710
#include <iostream> using namespace std; int main() { char *pc; int *pi; double *pd; pc = (char *)10000; pi = (int *)10000; pd = (double *)10000; cout << "증가 전 pc = " << (void *)pc << “ pi = " << pi << “ pd = " << pd << endl; pc++; pi++; pd++; cout << "증가 후 pc = " << (void *)pc << “ pi = " << pi << “ pd = " << pd << endl; return 0; } 증가 전 pc = pi = pd = 증가 후 pc = pi = pd = 16진수

28 포인터와 배열 배열 이름은 첫 번째 배열 원소의 주소 포인터를 사용하여서 배열 원소를 처리 가능

29 예제 #include <iostream> using namespace std; int main(void) {
const int STUDENTS = 5; int grade[STUDENTS] = { 10, 20, 30, 40, 50 }; for(int *p=grade, *pend=grade+STUDENTS; p != pend; p++) cout << *p << " "; return 0; }

30 배열과 함수 배열을 함수의 인수로 전달하는 경우에는 배열 이름이 포인터이므로 포인터가 전달된다.

31 예제 #include <iostream>
int get_average(const int score[], int n); void increment(int score[], int n); int main(void) { const int STUDENTS=5; int grade[STUDENTS] = { 1, 2, 3, 4, 5 }; int avg; increment(grade, STUDENTS); avg = get_average(grade, STUDENTS); cout << "평균은 “ << avg << “입니다.\n”; return 0; } void increment(int score[], int n) // 함수정의 int i; for(i = 0; i < n; i++) ++score[i];

32 예제 int get_average(const int score[], int n) // ② { int i;
int sum = 0; for(i = 0; i < n; i++) sum += score[i]; return sum / n; } 평균은 4입니다. 계속하려면 아무 키나 누르십시오 . . .

33 const와 포인터 const 객체에 대한 포인터 객체를 가리키는 const 포인터 const double *p;
double d = 1.23; p = &d; // 가능! *p = 3.14; // 컴파일 오류! double d = 1.23; double *const p=&d; *p = 3.14; // 가능! p = p + 1; // 컴파일 오류! p는 변경될 수 없다.

34 const 포인터 const int *p1; p1은 const int에 대한 포인터이다. 즉 p1이 가리키는 내용이 상수가 된다. *p1 = 100;(Ⅹ) int * const p2; 이번에는 정수를 가리키는 p2가 상수라는 의미이다. 즉 p2의 내용이 변경될 수 없다. p2 = p1; (Ⅹ)

35 void 포인터 C++에서는 묵시적인 포인터 변환은 허용되지 않는다. int *pi; double *pd; void* vp;
vp = pi; pd = vp; 1>c:\sources\test\test\test.cpp(18) : error C2440: '=' : 'void *'에서 'double *'(으)로 변환할 수 없습니다. 1> 'void*'에서 'void'가 아닌 포인터로 변환하려면 명시적 캐스트가 필요합니다. 1>빌드 로그가 "file://c:\sources\test\test\Debug\BuildLog.htm"에 저장되었습니다. 1>test - 오류: 1개, 경고: 0개 ========== 빌드: 성공 0, 실패 1, 최신 0, 생략 0 ==========

36 중간 점검 문제 배열의 첫 번째 원소의 주소를 계산하는 2가지 방법을 설명하라. 배열 a[]에서 *a의 의미는 무엇인가?
배열의 이름에 다른 변수의 주소를 대입할 수 있는가? 포인터를 이용하여 배열의 원소들을 참조할 수 있는가? 포인터를 배열의 이름처럼 사용할 수 있는가? 함수의 매개 변수로 전달된 배열을 변경하면 원본 배열이 변경되는가? 배열을 전달받은 함수가 배열을 변경하지 못하게 하려면 어떻게 하여야 하는가?

37 동적 메모리 동적 메모리 실행 도중에 동적으로 메모리를 할당받는 것 사용이 끝나면 시스템에 메모리를 반납
필요한 만큼만 할당을 받고 메모리를 매우 효율적으로 사용 new와 delete 키워드 사용 In C, malloc, free

38 동적 메모리 할당의 과정 #include <iostream> using namespace std;
int main() { int *pi; // 동적 메모리를 가리키는 포인터 pi = new int[100]; // ①동적 메모리 할당 for(int i=0; i < 100; i++) *(pi+i) = 0; // ②동적 메모리 사용 delete[] pi; // ③동적 메모리 반납 return 0; }

39 동적 메모리 할당과 반납 int *pi = new int; // 하나의 int형 공간할당
int *pia = new int[100]; // 크기가 100인 int형 동적배열할당 double *pd = new double; // 하나의 double형 공간할당 double *pda = new double[100]; // 크기가 100인 double형 동적배열할당 delete pi; // 동적할당int형공간반납 delete[] pia; // 동적할당배열반납 delete pd; // 동적할당double형공간반납 delete[] pda; // 동적할당배열반납

40 중간 점검 문제 1. 프로그램의 실행 도중에 메모리를 할당받아서 사용하는 것을 __________이라고 한다.
2. 동적으로 메모리를 할당받을 때 사용하는 키워드는 ______이다. 3. 동적으로 할당된 메모리를 해제하는 키워드는 ______이다.

41 참조자 참조자(reference): 변수에 별명을 붙이는 것 int &ref = var;
“참조자 ref은 변수 var의 별명(alias)이다”

42 예제 #include <iostream> using namespace std; int main() {
int var; int &ref = var; // 참조자선언 var = 10; cout << "var의값: " << var << endl; cout << "ref의값: " << ref << endl; ref = 20; // ref의 값을 변경하면 var의 값도 변경된다. return 0; } var의 값: 10 ref의 값: 10 var의 값: 20 ref의 값: 20

43 참조자와 포인터 참조자는 반드시 선언과 동시에 초기화 int &ref; // 오류!
포인터는 변경될 수 있지만 참조자는 변경이 불가능하다. int &ref = var1; ref = var2; // 오류! 참조자를 상수로 초기화하면 컴파일 int &ref = 10; // 오류!

44 예제 int n=10, m=20; int &ref = n; ref = m;// 컴파일 오류!!
변경 불가 초기화되지 않았음 상수로 초기화할 수 없음

45 예제 void dec_by_r(int& r) { // r은 time의 참조자이다. r--; // time이 감소된다.
return; } void dec_by_p(int* p) { --(*p); // time이 감소된다. int main() { int time = 10; dec_by_r(time); // time을 전달한다. dec_by_p(&time); // time의 주소를 전달한다. return 0;

46 참조자를 통한 효율성 향상 객체의 크기가 큰 경우, 복사는 시간이 많이 걸린다. 이때는 참조자로 처리하는 것이 유리

47 참조자를 통한 변경을 방지하려면 const를 앞에 붙이면 참조자가 가리키는 내용이 변경 불가능한 상수라는 뜻
void print(const int& r) { cout << "현재의 값= " << r << endl; return; } int main() print(100); reurn 0;

48 포인터 vs 참조자 일반적으로 참조자를 사용하는 편이 쉽다. 만약 참조하는 대상이 수시로 변경되는 경우에는 포인터를 사용
NULL이 될 가능성이 있는 경우에도 포인터를 사용 int *p = new int; if( p != NULL ) { int &ref = *p; ref = 100; } 오류

49 중간 점검 문제 1. 포인터와 참조자의 차이점을 설명하라. 2. 참조자보다 포인터를 사용하여야 하는 경우는?
3. 함수가 참조자를 반환할 수 있는가?

50 포인터와 함수 C++에서의 인수 전달 방법 값에 의한 호출 (call-by-value)
함수로 복사본이 전달된다. 참조에 의한 호출 (call-by-reference) 함수로 원본이 전달된다.

51 값에 의한 호출

52 swap() 함수 변수 2개의 값을 바꾸는 작업을 함수로 작성 #include <iostream>
using namespace std; void swap(int x, int y); int main() { int a = 100, b = 200; cout << "swap() 호출전: a = " << a << ", b = " << b << endl; swap(a, b); cout << "swap() 호출후: a = " << a << ", b = " << b << endl; return 0; }

53 값에 의한 호출 void swap(int x, int y) { int tmp; tmp = x; x = y; y = tmp; }
swap() 호출전: a = 100, b = 200 swap() 호출후: a = 100, b = 200 계속하려면 아무 키나 누르십시오 . . .

54 참조에 의한 호출 포인터를 시용하는 방법 참조에 의한 호출 참조자를 이용하는 방법

55 참조에 의한 호출(포인터 이용)

56 참조에 의한 호출(포인터) #include <iostream> using namespace std;
void swap(int &rx, int &ry); int main() { int a = 100, b = 200; cout << "swap() 호출전: a = " << a << ", b = " << b << endl; swap(a, b); cout << "swap() 호출후: a = " << a << ", b = " << b << endl; return 0; } void swap(int &rx, int &ry) int tmp; tmp = *px; *px = *py; *py = tmp; swap() 호출전: a = 100, b = 200 swap() 호출후: a = 200, b = 100

57 참조에 의한 호출(참조자)

58 참조에 의한 호출(참조자) #include <iostream> using namespace std;
void swap(int &rx, int &ry); int main() { int a = 100, b = 200; cout << "swap() 호출전: a = " << a << ", b = " << b << endl; swap(a, b); cout << "swap() 호출후: a = " << a << ", b = " << b << endl; return 0; } void swap(int &rx, int &ry) int tmp; tmp = rx; rx = ry; ry = tmp; swap() 호출전: a = 100, b = 200 swap() 호출후: a = 200, b = 100

59 중간 점검 문제 1. 함수에 매개 변수로 변수의 복사본이 전달되는 것을 ____________라고 한다.
2. 함수에 매개 변수로 변수의 원본이 전달되는 것을 ____________라고 한다. 3. 배열을 함수의 매개 변수로 지정하는 경우, 배열의 복사가 일어나는가?

60 문자표현방법 컴퓨터에서는 각각의 문자에 숫자코드를 붙여서 표시한다. 아스키코드(ASCII code): 표준적인 8비트 문자코드
0에서 127까지의 숫자를 이용하여 문자표현 유니코드(unicode): 표준적인 16비트 문자코드 전세계의 모든 문자를 일관되게 표현하고 다룰 수 있도록 설계

61 문자열 표현 방법 문자열(string): 문자들이 여러 개 모인것 "A" "Hello World!"
"변수 score의 값은 %d입니다“

62 C++에서 문자열을 나타내는 방법

63 C-문자열

64 문자 배열의 초기화 문자 배열 원소들을 중괄호 안에 넣어주는 방법
char str[6] = { 'H', 'e', 'l', 'l', 'o', '\0' }; 문자열 상수를 사용하여 초기화하는 방법 char str[6] = "Hello";· 만약 배열을 크기를 지정하지 않으면 컴파일러가 자동으로 배열의 크기를 초기화값에 맞추어 설정 char str[] = "C Bible"; // 배열의 크기는 7이 된다.

65 문자 배열에 문자를 저장 각각의 문자 배열 원소에 원하는 문자를 개별적으로 대입하는 방법이다. str[0] = 'W';
str[1] = 'o'; str[2] = 'r'; str[3] = 'l'; str[4] = 'd'; str[5] = '\0'; strcpy()를 사용하여 문자열을 문자 배열에 복사 strcpy(str, "World");

66 예제 #1 #include <iostream> using namespace std; int main() {
char str1[7] = "Seoul "; char str2[3] = { 'i', 's' }; char str3[] = " the capital city of Korea."; cout << str1 << str2 << str3 << endl; return 0; } Seoul is the capital city of Korea.

67 문자열 길이 계산 예제 // 문자열의 길이를 구하는 프로그램 #include <iostream>
using namespace std; int main() { char str[30] = "C++ language is easy"; int i = 0; while(str[i] != 0) i++; cout << "문자열 "<< str << "의 길이는 " << i << "입니다." << endl; return 0; } 문자열 C++ language is easy의 길이는 20입니다. 계속하려면 아무 키나 누르십시오 . . .

68 문자열 처리 라이브러리 #include <cstring> H e l o W r d 함수 설명 strlen(s)
strcpy(s1, s2) s2를 s1에 복사한다. strcat(s1, s2) s2를 s1의 끝에 붙여넣는다. strcmp(s1, s2) s1과 s2를 비교한다. strncpy(s1, s2, n) s2의 최대 n개의 문자를 s1에 복사한다. strncat(s1, s2, n) s2의 최대 n개의 문자를 s1의 끝에 붙여넣는다. strncmp(s1, s2, n) 최대 n개의 문자까지 s1과 s2를 비교한다. strchr(s, c) 문자열 s안에서 문자 c를 찾는다. strstr(s1, s2) 문자열 s1에서 문자열 s2를 찾는다. #include <cstring> H e l o W r d

69 예제 // strcpy와 strcat #include <iostream>
#include <cstring> using namespace std; int main() { char string[80]; strcpy( string, "Hello World from " ); strcat( string, "strcpy() " ); strcat( string, "and " ); strcat( string, "strcat()!" ); cout << string << endl; return 0; } Hello World from strcpy() and strcat()!

70 중간 점검 문제 1. C-문자열 src를 C-문자열 dst로 복사하는 문장을 써라.
2. “String"을 저장하려면 최소한 어떤 크기 이상의 문자 배열이 필요한가? 3. 문자열을 서로 비교하는 함수는?

71 Q & A

72 Programming 1. 배열 days[]를 아래와 같이 초기화하고 배열 원소의 값을 다음과 같이 출력하는 프로그램을 작성하라. int days[] = {31,29,31,30,31,30,31,31,30,31,30,31};

73 Programming 4. 0부터 9까지의 난수를 100번 생성하여 가장 많이 생성된 수를 출력하는 프로그램을 작성하시오.
int main() { srand(time(NULL)); cout<<"0부터 9까지의 난수를 100번 생성하여 가장많이 생성된 수는 ?\n"; GetNum(100); return 0; }


Download ppt "C++ Espresso 제3장 배열과 포인터."

Similar presentations


Ads by Google