시간 | 2021년 7월 13일 화요일 20:00 ~ 22:00 |
장소 | ZOOM |
참가자 | - |
출처: 천인국, “어서와 C++는 처음이지!”, INFINITY BOOKS
https://boycoding.tistory.com/category [소년코딩]
만약 포인터가 선언만 되고 초기화되지 않았다면 포인터는 임의의 주소를 가리키게 됩니다. 따라서 이런 상태에서 포인터를 사용하여 메모리의 내용을 변경한다면 문제가 발생합니다.
int *p; //포인터 p는 초기화가 안 되어 있음 *p = 100; //위험한 코드그래서 포인터가 아무것도 가리키고 있지 않을 때는 nullptr로 설정하는 것이 바람직합니다. 왜냐하면 nullptr을 사용하여서 어딘가에 접근하려하면 시스템에서 자동적으로 오류를 감지할 수 있기 때문입니다.
int *p = nullptr;
C++은 세 가지 기본 타입의 메모리 할당을 지원합니다.
1. 정적 메모리 할당(static memory allocation)은 정적 변수와 전역변수에 대해 발생한다. 이러한 타입의 변수에 대한 메모리는 프로그램이 실행될 때 한 번 할당되며, 프로그램 수명 내내 지속한다.
2. 자동 메모리 할당(auto memory allocation)은 함수 매개 변수와 지역 변수에 대해 발생한다. 이러한 타입의 변수에 대한 메모리는 관련 블록을 입력할 때 할당되고, 블록을 종료할 때 필요에 따라 여러 번 해제된다.
3. 동적 메모리 할당(dynamic memory allocation)은 이 스터디의 주된 내용이다.
정적 및 자동 메모리 할당에는 두 가지 공통점이 있다.
⦁변수/배열의 크기는 컴파일 할 때 알아야 한다.
⦁메모리 할당 및 해제가 자동으로 수행된다. (변수가 인스턴스화/제거되는 경우)
그래서 외부(사용자 또는 파일) 입력을 처리할 때(ex. cin으로 배열 크기를 받아오고 싶을 때) 이러한 제약 조건으로 인해 문제가 발생하는 상황이 생길 수 있다.
예를 들어, 문자열을 사용하여 누군가의 이름을 저장할 수 있지만, 입력할 때까지 이름의 길이를 알 수 없습니다. 또는 디스크에서 여러 레코드를 읽으려고 할 수 있지만, 실제로 얼마나 많은 레코드가 있는지 알 수 없다. 또한, 게임에서 얼마나 많은 몬스터를 가지는 배열을 만들어야 하는지 알 수 없다.
컴파일 시간에 모든 것의 크기를 선언해야 한다면, 할 수 있는 최선의 방법은 필요로 하는 변수의 최대 크기를 추측하고 충분하다고 가정하는 것이다.
char name[25]; // let's hope their name is less than 25 chars! Record record[500]; // let's hope there are less than 500 records! Monster monster[40]; // 40 monsters maximum위 프로그램은 몇 가지 이유로 좋지 않다.
동적 메모리는 new 연산자를 이용하여서 할당된다. new 뒤에는 자료형을 적는다. 만약 하나 이상의 요소가 필요하다면 [ ] 안에 요소의 숫자를 적습니다. 이는 아래서 이야기할 1차원 배열과 관련이 있다. new 연산자는 할당되는 동적 메모리의 시작 주소를 반환한다.
int *p; //포인터 선언 p = new int; //p는 동적 메모리를 가리키는 포인터, int는 동적 메모리의 타입 p = new int[N]; //[N]은 동적 메모리의 개수 p = new int[N] {x1, x2, ---, xN};. //{ }안 의 값은 동적 메모리의 초기값들이제 동적 메모리를 사용하는 법을 알았으니 동적 메모리를 해제하는 방법을 알아보자.
delete p; delete [] p;동적 할당받은 메모리 공간을 반납하려면 위와 같은 방법을 사용하면 됩니다. 주의할 점은 만약 p = new int[10];과 같이 할당한 경우는 반드시 delete [] p;로 해제해야한다.
이제 동적 메모리 할당을 통해 1차원 배열을 다뤄보자.
우선 배열을 할당하고 해제하는 방법은 위에서도 언급했다.
int *p; //포인터 선언 p = new int[5]; //int형 변수 5개를 저장할 수 있는 공간 할당 delete [] p;위의 문장을 실행하면 int형 변수 5개를 저장할 수 있는 공간이 할당되고 첫 번째 변수를 가리키는 주소를 반환한다.
#include <iostream> using namespace std; int main() { int length = 3; int* array = new int[length](); for (int i = 0; i < length; i++) cout << array[i] << endl; array = new int[5]{ 9, 7, 5, 3, 1 }; for (int i = 0; i < 5; i++) cout << array[i] << endl; delete[] array; return 0; }단 초기화 할 때 동적 배열은 명시적으로 길이를 설정해 선언해야 한다.
int fixedArray[] {1, 2, 3}; // okay: implicit array size for fixed arrays int* dynamicArray1 = new int[] {1, 2, 3}; // not okay: implicit size for dynamic arrays int* dynamicArray2 = new int[3] {1, 2, 3}; // okay: explicit size for dynamic arrays
정수 5개를 저장할 수 있는 동적 배열 생성후 난수를 저장해 출력하기
#include <iostream> #include <ctime> using namespace std; int main() { int *ptr; srand(time(NULL)); ptr = new int[10]; for (int i = 0; i<10; i++) ptr[i] = rand(); for (int i = 0; i<10; i++) cout << ptr[i] << " "; delete[] ptr; cout << endl; return 0; }
앞에서는 포인터로 1차원 배열을 다뤘다. 이번에는 이중 포인터 또는 그 이상을 이용하면 다차원 배열을 다룰 것이다.
동적으로 포인터의 배열을 할당할 때 이중 포인터를 사용하는 방법은 앞에서 배운 방법보단 복잡하다. 2차원 고정 배열 선언은 몹시 간단하다.
int array[10][5];그렇다면 처음에는 동적으로 2차원 배열을 할당할 때 이런 식으로 시도할 수 있을 것이다.
int** array = new int[10][5]; //잘못된 코드하지만 위의 코드는 작동하지 않을 것이다. 이제 제대로 동적으로 2차원 배열을 할당해보자.
int** m = new int*[3]; // 행(row)의 개수가 3이다. for (int row = 0; row < 10; row++) m[row] = new int[4]; //열(column)의 개수가 4이다.
m[2][1] = 3;2차원 동적 배열을 할당할 때 루프를 사용한 것처럼 해제하려면 루프가 필요하다.
for (int row = 0; row < 10; row++) delete[] m[row]; delete[] m;이때 반드시 할당한 순서의 반대로 해제해야 한다. 왜냐하면 전체 배열을 먼저 해제하면 배열의 요소를 해제하기 위해 전체 배열에 접근해야 하는데 이때 정의되지 않은 동작이 발생한다.
#include <iostream> using namespace std; int main() { int row=0, col=0; cout << "열과 행 입력: "; cin >> row >> col; int** m = new int* [row]; for (int i = 0; i < row; i++) m[i] = new int[col]; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) m[i][j] = i + j; } for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) cout<<m[i][j]<<" "; cout << endl; } for (int i = 0; i < row; i++) delete[]m[i]; delete[]m; return 0; }
입력받을 이름 개수를 입력받고 이름을 입력한 후 입력받은 이름들 출력하기
Tip. 문자열을 저장하는 동적 배열은 string* names = new string[length]; 와 같이 생성한다.