C++ study(9)

김혜원·2023년 1월 31일
0

c++study

목록 보기
9/11

배열의 동적 할당

동적배열dynamic allocating 의 주 목적인 크기를 모르는 배열을 동적 할당해 보자!

#include <iostream>
using namespace std;

int main()
{
	int *arr;
	arr = new int[10];

	for (int i = 0; i < 10; i++)
		arr[i] = i + 1;

	int sum = 0;
	for (int i = 0; i < 10; i++)
		sum += arr[i];

	cout << sum << endl;

	delete[] arr;

	return 0;
}

배열을 할당할 경우, (1차원 배열에서) 받는 것은 그대로 포인터이다.
new로 배열 메모리를 할당받을 때, 자료형 뒤에 "[크기]" 를 이어서 쓴다. c에서 처럼 byte수로 넘겨야 해 sizeof(int)를 곱하거나 하는 일은 없다. 이미 자료형이 언급되었으므로 "크기"만 주면 된다.
delete로 배열 메모리를 해제할 때는 "delete[]" 로 쓴다.
[] 를 붙이면 포인터가 배열을 할당받았으므로 연달아 많은 칸의 메모리를 해제해야 한다는 것을 컴퓨터에 알려주어 이어진 메모리를 한번에 다 해제한다.

class와 배열 동적 메모리의 결합!

#include <iostream>
using namespace std;

class Student
{
private:
	string name;
	int score;

public:
	Student();
	Student(string, int);
	int getScore();
};

int main()
{
	int num;
	string tname;
	int tscore;
	Student *student_arr;

	cout << "enter number of students:";
	cin >> num;
	student_arr = new Student[num];

	for (int i = 0; i < num; i++)
	{
		cout << i + 1 << " 'th student's name:";
		cin >> tname;
		cout << i + 1 << " 'th studnet's score(0~100): ";
		cin >> tscore;
		student_arr[i] = Student(tname, tscore);
	}

	int sum_score = 0;

	for (int i = 0; i < num; i++)
		sum_score += student_arr[i].getScore();

	cout << "Score's sum:" << sum_score << endl;

	delete[] student_arr;

	return 0;
}

Student::Student() : name(""), score(0) {}

Student::Student(string tname, int tscore) : name(tname), score(tscore) {}

int Student::getScore()
{
	return score;
}

입력받는 변수 num이 배열의 크기를 결정한다. 이때 배열의 크기를 사용한 메모리의 동적할당을 할 때, Student[num] 과 같은 형식으로 해주었다.

dangling pointer

가리키는 곳이 정해지지 않은 포인터로, 가리키는 주소를 초기화하지 않았거나, 동적 메모리 할당 후 해제를 한 직후에 발생한다. 후자의 경우, 가리키던 메모리가 해제되어 그 주소는 더 이상 쓸모 없다. 이런 주소에 " *, [], -> " 같은 연사자들로 접근하려 하면 심각한 문제가 발생한다.

example of dangling pointer
#include <iostream>
using namespace std;

int main(){

int *p = new int[3];
p[0] = 4;
p[1] = 1;
p[2] = 7;
cout << p[0] << endl;
cout << p[1] << endl;
cout << p[2] << endl;
delete[] p;
cout << p[0] << endl;
cout << p[1] << endl;
cout << p[2] << endl;

return 0;
}

메모리 할당 해제 이후 그 메모리에 젖ㅂ근하려 하면 쓰레기값 밖에 건지지 못한다.
이미 해제된 메모리를 참조하지 않기 위해 해제 후 해당 포인터를 NULL pointer로 만든다. NULL pointer로 접근하려 하면 실행 중 에러가 떠 논리적 오류를 잡을 수 있다.

동적 메모리를 놓쳐 해제를 못 하는 경우

#include <iostream>
using namespace std;

int main(){

int *p = new int(12);
int *q = new int(45);
cout << p << " " << q << endl;

q = p;
cout << p << " " << q << endl;

return 0;
}

p,q가 서로다른 동적 메모리를 가리키고 있는데, q=p; 명령으로 인해 q가 가리키고 있던 동적 메모리에 접근할 방법이 사라졌다. 이렇게 되면 q가 가리키고 있던 동적 메모리를 해제할 수 없게 된다.

동적 메모리와 일반적인 auto형 지역 변수의 차이
#include <iostream>
using namespace std;

int *getPtr()
{
	int n = 5;
	int *p = &n;
	return p;
}

int main()
{
	int *q;
	q = getPtr();
	cout << *q << endl;

	return 0;
}

포인터 형(주소값)을 return하는 함수를 만들었다. return 값이 지역변수인 n의 주소값인데, 함수 종료 후 그에 속한 지역변수 n도 날아가게 되어 return값은 dangling 포인터가 된다. //컴파일러에 따라 쓰레기값이 아닌 n값이 나오기도 한다..

#include <iostream>
using namespace std;

int *getPtr()
{
	int *p = new int(5);
	return p;
}

int main()
{
	int *q;
	q = getPtr();
	cout << *q << endl;

	delete q;

	return 0;
}

함수 안에서 동적 메모리를 할당받아 그 주소를 넘겨줬다면, 메모리는 heap에 별개 위치하므로, 항상 원했던 값인 *p값이 나오게 된다. 함수가 끝나도 메모리는 함수 종료와 관계없이 남아있다. 단, 이 메모리는 언젠가는 해제해 줘야 한다. 다라서 마지막 줄에 delete해 주었다.

0개의 댓글