본문 바로가기
공부

C++ 메모리영역 복습

by MY블로그 2022. 12. 1.

메모리 영역에 대한 복습이다. 주로 각 영역에 저장되는 것들을 한번에 알아보기 위해서 작성하였다.

기존 공부 자료 에 부족함이 보여 추가적으로 복습한다.
https://rhksgml78.tistory.com/43

메모리의 관리(구조/스택프레임/동적할당)

메모리의 구조 프로그램이 실행되려면 우선 프로그램이 메모리에 로드(load)되어야 한다. 프로그램에서 사용되는 변수들을 저장할 메모리가 필요하다. 이에따라 컴퓨터의 운영체제는 프로그램

rhksgml78.tistory.com

이전 공부했던 자료를 참조하여 메모리의 각영역에 저장되는 것들을 나누어 보고자 한다.

◆프로세스 메모리 영역
  • 프로세스 : 현재 실행중인 프로그램
◆커널(Kernel) 영역
  • 윈도우즈(Windows)가 사용하는 공간
  • 단일 공간으로 커널 모드를 사용하는 모든 프로세스에 공유된다.
  • 시스템 운영에 필수적이기 때문에 RAM에 존재한다.

주기억장치 & 보조기억 장치 기존 조사 자료를 참조하자
https://rhksgml78.tistory.com/5

주기억 장치&보조기억 장치

▶주기억장치◀ (Computer Memory / Primary Memory) 주기억 장치는 컴퓨터안의 CPU가 처리하는 내용을 저장하는 기억장치 비교적 용량이 크고 처리 속도가 빠른편, CPU의 명령에 의해 기억된 저장 장소에

rhksgml78.tistory.com

◆코드(CODE) 영역
  • 이름공간, 함수, 제어문에 대한 기계어 코드가 저장됨
  • 문자열의 상수를 제외한 지역변수에 해당되는 리터럴 상수(Literal Constant)가 기계어로 저장
  • 작성한 코드가 저장되는 공간
  • 라이프 타임 : 프로그램 시작 ~ 종료 까지
◆데이터(DATA) 영역
  • .rodata : 읽기전용으로 초기화되는 영역(const선언),전역변수,정적변수,배열,구조체,문자열 저장
  • .data : 0이아닌 값으로 초기화된 전역변수 혹은 정적변수 저장 (읽기,쓰기 가능한 영역)
  • .bss : 0으로 초기화, 초기화 되지않은 전역변수, 정적변수를 저장 (Block Started Symbol)
  • 전역변수, 정적변수(static)
  • 모든 전역 변수는 별도로 초기화되지 않으면 모두 0으로 초기화된다.
  • 라이프 타임 : 프로그램 시작 ~ 종료 까지
◆스택(STACK) 영역
  • 지역변수(로컬변수)(매개변수 포함) 저장
  • LIFO (후입선출 : Last In First Out)
  • 로컬 변수는 const 키워드가 붙어도 스택 영역에 저장된다.(필드 종료시 삭제되어야 하기때문)
  • 라이프 타임 : 필드 '{'시작 ~ 종료'}' 까지
◆힙(HEAP) 영역
  • 동적 할당 변수 (C : malloc / C++ : new)
  • 프로그램 동작 중 사용자가 원할 때 생성하고 원할때 해제 할수있는 변수들이 저장
  • 라이프 타임 : 동적할당 ~ 해제 까지 (C++ : new ~ delete 까지)
◆기타 메모리 공간에 할당되지 않는 것들
  • 매크로 상수 (Macro Constant) = #define 전처리 과정에서 치환되므로 메모리공간 할당 x
  • 열거체 (Enumeration) = 정수 값에 이름을 붙인 형태 > 정수형으로 치환 메모리공간 할당x

#define 그리고 enum 열거체는 Black Jack 게임 작성 코드에서 한번에 확인 할수 있다.
블랙잭 코드는 접은글로 첨부한다.

더보기
#include <iostream>
#include <time.h>
#include <string>
#include <vector>
#define SET 3

using namespace std;

enum Shape //모양 함수 4종류
{
	DIA,
	CLOVER,
	HEART,
	SPADE
};

enum Num //특정숫자는 문자출력을 위한 함수
{
	A = 1,
	J = 11,
	Q,
	K
};

struct Card // 구조체 카드 (숫자, 모양, 특정숫자는 문자변환출력)
{
	int num;
	string shape;

	void Print()
	{
		switch (num)
		{
		case A:
			cout << shape << "A" << "\t";
			break;
		case J:
			cout << shape << "J" << "\t";
			break;
		case Q:
			cout << shape << "Q" << "\t";
			break;
		case K:
			cout << shape << "K" << "\t";
			break;
		default:
			cout << shape << num << "\t";
			break;
		}
	}
};

struct Player //플레이어 구조체 (이름 돈 카드 점수 승패 카드패출력)
{
	string name;
	int money;
	vector<Card>card;
	int jokbo = 0; //카드의합 초기화 = 처음상태는 0
	bool win; //승패용 변수

	void MakeJokbo(bool dealer = 0)
	{
		jokbo = 0;
		int select; //플레이어의 패중에 A의카드가있을시 1또는 11점수 선택용 변수
		for (int i = 0; i < card.size(); i++) //카드갯수만큼 반복시킬 반복문
		{
			if (card[i].num > 10) //카드의 넘버가 10이상인경우는 무조건 10만 더해지도록설정
			{
				jokbo += 10;
			}
			else if (card[i].num == 1) //카드가 1 즉,카드가 A패일 경우
			{
				if (!dealer) // 딜러가아닐때 = 즉, 플레이어일때
				{
					for (int i = 0; i < card.size(); i++) // 카드패만큼반복하면서 출력시킴
					{
						card[i].Print();
					}
					
					cout << "A카드획득. 카드점수선택. [1]=1점 / [2]=11점 "; //점수선택 출력
					cin >> select; //선택 입력

					if (select == 1) //1번선택
					{
						jokbo += 1; // 1번카드는 점수1점
					}
					else if (select == 2) // 2번선택
					{
						jokbo += 11; // 1번카드는 점수11점
					}
				}
				else
				{
					jokbo += 1; //그외에는 그냥 A카드 1점더하기
				}
			}
			else // a카드가 아니고 다른카드일경우 그냥 일반점수더하기
			{
				jokbo += card[i].num;
			}

		}
	}

	void Print(bool dealer = 0)
	{
		cout <<"["<< name<<"]" << "\t";
		for (int i = 0; i < card.size(); i++) // 딜러도 플레이어도 점수는 출력된다
		{
			card[i].Print();
		}
		cout << "점수 : " << jokbo << "\t";
		if (!dealer) //딜러가아니라면 = 플레이어라면 소지금 출력
		{
			cout << "소지금 : " << money << "\t";
		}
		cout << endl;
	}
};

Card MakeDeck(int num, string shape) //카드덱 만들기, 구조체안에있는 숫자 모양 불러오기
{
	Card temp; // 카드덱의 빈 인덱스 생성
	temp.num = num; // 빈인덱스의 숫자생성
	temp.shape = shape; // 빈인덱스의 모양생성
	return temp; // 빈인덱스 반환
}

void Shuffle(vector<Card>& deck) //카드섞기(셔플) 벡터로할당된 카드구조체의 덱주소
{
	for (int i = 0; i < 1000; i++) //대충 천번정도 셔플해주기
	{
		int sour = rand() % (52 * SET); //52개의 카드 총 SET갯수 전부 셔플해준다.
		int dest = rand() % (52 * SET);

		Card temp = deck[sour]; //기본셔플형식. 단 카드구조체셔플.
		deck[sour] = deck[dest];
		deck[dest] = temp; 
	}
}

//===============================================================================함수구성끝

int main() // 메인 시작
{
	srand(time(NULL));
	vector<Card>deck;
	Player* player;
	Player dealer;

	int cardCount = 0; //카드의 합계산을위한 초기화
	int input;
	int size;

	//덱만들기
	for (int i = 0; i < 52*SET; i++) // 총카드는 52개가한묶음으로 define SET 갯수만큼 곱해진다.
	{ // 52개의 묶음 *3 이기때문에 같은카드는 3개까지 나오게된다.
		string temp;
		int cut = i % 52; // 0~51까지 카운트후 다시 0부터 51까지만 카운트되도록

		switch (cut / 13) // 52개의 카드는 4종류의 모양으로 나뉜다. 초 4종 각각 13장씩 52장
		{
		case DIA:
			temp = "◆";
				break;
		case CLOVER:
			temp = "♣";
				break;
		case HEART:
			temp = "♥";
				break;
		case SPADE:
			temp = "♠";
				break;
		}
		deck.push_back(MakeDeck(i % 13 + 1, temp));
	}

	//========================================== 게임 시작전 기본세팅
	cout <<"\t" << "[블랙잭 게임]"<<"\t" << endl;
	cout << endl;
	cout << "게임에 참가할 인원수를 입력해 주세요 : " << "\t"; cin >> size;
	cout << endl;
	
	player = new Player[size]; //플레이어의 인원수입력에따른 동적할당.

	for (int i = 0; i < size; i++) //참가인원수 만큼 반복하며 이름 입력받기
	{
		cout << i + 1 << "번 참가자의 이름을 입력 : " << "\t";
		cin >> player[i].name; // 구조체에 동적할당 받았기때문에 직접 palyer[i].name 에 접촉이 가능
		player[i].money = 100000; // 플레이어들의 소지금은 단순히 통일시킴.
	}

	dealer.name = "딜러"; // 딜러의 이름은 단순히 딜러
	dealer.money = 100000; // 딜러도 일단 금액설정해둔다.

	//=========================================== 본게임 시작

	while (true) //게임은 게속 반복 되도록 설정
	{
		cardCount = 0; //카드나누어줄때 같은 배열에있는 카드가 겹치지않도록 카운트초기화
		//0번배열에있는 카드부터 순차대로 나눠준다.
		//카드는 나눠줄때마다 배열순서대로 나눠준다 (배열은 셔플되어있음)
		Shuffle(deck); // 게임시작전 덱셔플해주기

		for (int i = 0; i < size; i++) //게임 인원수 설정만큼 반복
		{
			cout << endl;
			cout << "=======================================" << player[i].name << "의 차례입니다." << endl;
			cout << endl;
			player[i].win = true; //게임플레이어의 상태는 기본 참값으로 하여 진행되도록한다.
			player[i].money -= 1000; // 새게임마다 1천원씩 소지금 감소
			
			player[i].card.clear(); //새게임시작시 기존의 카드패는 초기화
			player[i].card.push_back(deck[cardCount]); //새로운 카드 벡터로 1장받는다
			cardCount++; //카드배열 하나증가. (0번카드 받고 다음받을수있는카드는 1번카드)
			player[i].card.push_back(deck[cardCount]); //새로운 카드 벡터로 1장받는다
			cardCount++; //카드배열 하나증가. (1번카드 받고 다음받을수있는카드는 2번카드)

			//카드를 받았다면 현재 카드의 합을 보여준뒤 더받을지 멈출지 확인하기
			player[i].MakeJokbo(); //플레이어의 족보(카드의합)을 계산시킨다.
			
			//그리고나서 출력
			player[i].Print(); // 프린트 함수를 이용하여 소지카드 점수 소지금 등을 보이게한다.

			//출력이되어 확인하였으면 추가카드 받기여부
			while (true) //버스트하거나 그만받을때까지 반복한다
			{
				cout << "추가카드를 받으시겠습니까? [1]YES / [2]NO" << "\t"; cin >> input;
				if (input == 2)
				{
					break; // 카드를 더안받는선택시 반복문 탈출한다.
				}
				// 2번선택이 아니라면 아래 코드진행
				player[i].card.push_back(deck[cardCount]); //카드한장만 더받고
				cardCount++; // 이후 제공될 카드 인덱스카운트 증가
				player[i].MakeJokbo(); // 카드를 받아서 다시 점수 계산을하고
				player[i].Print(); // 출력시킨다 

				if (player[i].jokbo > 21) //플레이어의 카드점수가 21점이 넘어갔을경우
				{
					cout << player[i].name << "참가자가 버스트 ! " << endl;
					player[i].win = false; // 플레이어의 승리가 거짓값으로 바뀐다 = 패배.
					break; //진행중인 반복문을 탈출한다.
				}
				else
				{
					player[i].win = true; // 카드합계가 21이넘지않는한 플레이어의 상태는 그대로이다.
				}
			}
		}
		//플레이어 설정후 딜러 설정
		dealer.win = true; //딜러의 상태도 기본 참값이다.
		dealer.card.clear(); //딜러도 마찬가지로 게임시작때마다 패는 초기화 시킨다.
		dealer.card.push_back(deck[cardCount]);
		cardCount++;
		dealer.card.push_back(deck[cardCount]);
		cardCount++; // 딜러도 매판마다 카드 2장을 받으며 분배할카드 인덱스는 줄때마다증가.
		cout << endl;
		cout << "=======================================" << dealer.name << "의 차례입니다." << endl;
		cout << endl;
		//딜러패의 합계산
		dealer.MakeJokbo(true); // 함수의 매개변수가 참인이유는 함수는 플레이어 함수에 들어가지않게하기위해서

		//딜러패의 출력
		dealer.Print(true); // 매개변수가 참인이유는 위와 동일.

		//딜러는 카드의합이 17미만인경우 자동적으로 카드를 더 받도록 설정한다.
		while (dealer.jokbo < 17)
		{
			dealer.card.push_back(deck[cardCount]); //조건에일치하면 카드한장을 더받고
			cardCount++; //카드인덱스 1증가
			dealer.MakeJokbo(true); //딜러패의 점수 계산
			dealer.Print(true); //게산후 출력

			if (dealer.jokbo > 21) //딜러의 점수가 21점이 넘으면 버스트시키고
			{
				cout << dealer.name << " 의 버스트 ! " << endl;
				dealer.win = false; //딜러의 상태는 패배가된다.

				for (int i = 0; i < size; i++) //플레이어 인원수만큼 반복문을 돌려서
				{
					if (player[i].win) //만약 플레이어의 상태가 win 이라면
					{
						cout << player[i].name << " 승리 ! " << endl; //해당플레이어의 승리
						player[i].money += 3000; //승리한 플레이어는 소지금이 3천원 추가된다.
					}
				}
				break; // 반복문을 탈출한다.
			}
			else
			{
				dealer.win = true; // 점수의 합이 21만넘지않는다면 패배상태가 아니다.
			}
		}
		//반복문 내에서 승패 비교까지 이루어져야한다.
		for (int i = 0; i < size; i++) // 승패조건의검사는 플레이어의 수만큼 반복되서 검사된다
		{
			if (dealer.win && player[i].win) // 딜러와 플레이어 양쪽이 버스트가 아닌상태에서
			{
				if (dealer.jokbo < player[i].jokbo) // 딜러의 점수보다 플레이어의 점수가 높다면
				{
					cout << player[i].name << " 승리 ! " << endl; //해당플레이어의 승리
					player[i].money += 3000; //승리한 플레이어는 소지금이 3천원 추가된다.
				}
				else if (dealer.jokbo = player[i].jokbo)
				{
					cout << player[i].name << " 패배 ! " << "\t"; 
					cout << "동점은 딜러 승리 입니다. " << endl;
					player[i].win = false;
				}
				else
				{
					cout << "딜러 승리 입니다 ! " << endl;
					cout << player[i].name << " 패배 ! " << endl;
					player[i].win = false;
				}
			}

		}

	}
	for (int i = 0; i < size; i++)
	{
		delete[i] player;
	}
	delete[] player;

	return 0;
}





댓글