서적 정리/C++ 기초 플러스

19.포인터, 배열, 포인터 연산

민돌이2 2022. 8. 9. 16:49

배열의 이름은 포인터와 비슷한 의미를 갖는다. 완벽히 같다고는 말하지 못해도 맥락은 같다고 할 수 있다. 배열의 이름은 배열의 시작 주소, 첫 번째 원소의 주소를 의미한다.

정수형 변수에 1을 더하면 값이 1만큼 증가한다. 하지만 포인터 변수에 1을 더하면 값이 포인터가 지시하는 데이터형의 byte 만큼 증가한다. 예를 들어 int형이 4byte인 환경에서 int형 포인터에 1을 더하면 8이 증가한다.

int main()
{	
	using namespace std;
	
	int a[3] = { 1,2,3 };
	int* b = a;

	cout << a << endl;
	cout << a + 1 << endl;
	cout << b << endl;
	cout << b + 1 << endl;

	system("Pause");
	
	return 0;
}

결과

16진수로 값을 저장하기 때문에 8 + 4 = 12 = C라는 점을 잊지 말아야 한다. 위 코드에서 배열 a로 포인터 값에 대입했다는 의미는 배열의 이름인 a는 주소라는 의미이다. 좀 더 들어가서 배열의 이름이 주소임을 활용해서 배열의 값을 알아 낼 수있다.

int main()
{	
	using namespace std;
	
	int a[3] = { 1,2,3 };
	int* b = a;

	cout << "a : ";
	for (int i = 0; i < 3; i++)
		cout << *(a + i) << " ";
	
	cout << endl << "b : ";

	for (int i = 0; i < 3; i++)
		cout << *(b + i) << " ";
	cout << endl;

	cout << endl;
	system("Pause");
	
	return 0;
}

결과

결론적으로, a[0]와 *a는 동등하고, a[2]와 *(a + 2)는 동등하다.

 

 

포인터와 문자열

문자열은 문자의 배열이다. 아무 생각없이 사용했던 코드가 있다.

char flower[10] = "rose";
cout << flower << "s are red\n";

배열의 이름은 첫 번째 원소의 주소를 의미한다. 2행의 flower은 문자r의 주소이다. 하지만 출력되는 값은 주소가 아니라 rose를 출력한다. 이는 cout 객체는 문자열의 주소라 간주하고 주소에 있는 문자를 출력한 후, NULL 문자(\0)를 만날 때까지 문자들을 출력한다.

 

 

new를 사용한 동적 구조체의 생성

구조체 역시 new를 사용하여 동적 구조체를 생성할 수 있다. 동적(dynamic)이란 컴파일 타임이 아닌 런 타임에 메모리를 대입받는다는 의미다. 구조체는 멤버 변수나 함수가 존재한다. 이때 평소와 다르게 도트(.) 멤버 연산자를 사용하는 것이 아닌, 화살표 멤버 연산자(->)를 사용해야 한다.

struct Inflatable
{
	char name[2];
	float volume;
	double price;
};

int main()
{	
	using namespace std;
	
	Inflatable* ps = new Inflatable;

	cout << "이름을 입력하세요 : ";
	cin.get(ps->name, 20);

	cout << "부피를 입력하세요 : ";
	cin >> ps->volume;

	cout << "가격을 입력하세요 :";
	cin >> ps->price;

	cout << "이름 : " << ps->name << endl;
	cout << "부피 : " << ps->volume << endl;
	cout << "가격 : " << ps->price << endl;

	delete ps;

	system("Pause");
	
	return 0;
}

결과

구조체 멤버에 접근하는 다른 방법이 있다. 안이쁘고 귀찮아서 사용하는 일은 드물 것이다.

(*ps).name; //ps->name;
(*ps).volume; //ps->volume;
(*ps).price; //ps->price;

 

 

 

자동 공간, 정적 공간, 동적 공간

C++에서는 데이터를 저장해 두기 위한 메모리를, 대입하는 방법에 따라 자동 공간(automatic storage), 정적 공간(static storage), 동적 공간(dynamic storage)으로 구분한다.

 

자동 공간(automatic storage)

함수 안에서 정의되는 보통의 변수들을 자동 변수(automatic variable)라고 한다. 자동 변수들은 함수가 호출되는 순간에 생겨나 그 함수가 종료되는 시점까지만 존재한다는 것을 뜻한다.

다른 말로 스택(stack) 영역이라고 하며, 주로 스택 영역으로 알고 있다. 스택에 저장되는 값은 순차적으로 저장되고, 역순으로 해제된다. 이를 후입선출(last-in first out : LIFO)라고 부른다.

 

정적 공간(static storage)

프로그램이 실행되는 동안에 지속적으로 존재하는 공간이다. 즉, 컴파일 타임때 생성되고, 프로그램 종료시 소멸된다.

변수를 정적으로 만드는 방법은 두 가지가 있다. 하나는 함수의 외부에서 변수를 정의하는 것이고, 하나는 함수 내부에서 static 키워드를 붙이는 것이다.

다른 말로 데이터(data) 영역, BSS 영역 이라고 한다. 데이터 영역과, BSS 영역의 차이는 컴파일 시 초기값의 유무이다. 초기값이 있다면 데이터 영역으로 할당되고, 없다면 BSS 영역으로 할당된다.

 

동적 공간(dynamic storage)

new 연산자를 사용하여 생성한 변수들은 동적 공간에 할당된다. 즉, 동적 할당한 변수들이 차지할 메모리 공간이다.

동적 할당한 시점에 생성되며, 개발자가 소멸하지 않으면 계속 남아 있다. 즉, 프로그램을 종료해도 남아 있어서 메모리 누수가 발생할 수 있다.

다른 말로 힙(heap) 영역이라고 한다. 

 

영역 메모리 할당 종류 메모리 할당 결정 시기
Code 함수, 제어문, 상수 등 함수에 대한 기계어 코드 compile time에 크기가 결정되고, 이후로 변동되지 않는다.
Data 초기값이 있는 전역 변수, 배열
BSS 초기값이 없는 전역 변수, 배열
Heap 동적 할당 run time에 크기가 결정되고, BSS와 heap 사이를 기준으로 heap은 아래에서 순차적으로, stack은 위쪽으로 순차적으로 메모리를 사용한다.
Stack 지역 변수, 매개 변수

 

728x90