외부스택vs내부스택. 메모리계층 구조. 스택포인터&프레임포인터에 대해 조사하고, 복사생성자와 대입연산자의 차이점 구분, 연산자 오버로딩 복습(오버로딩과 오버라이딩 설명&차이점)

 

메모리의 구조

 

  프로그램을 실행하기 위해 컴퓨터가 가장 먼저 하는 일은 프로그램 로드(load)이다. 흔히 로딩(loading)이라고 부르는 과정을 의미하며, 메모리에 프로그램을 불러오는 것을 의미한다. 이때, 프로그램에서 사용되는 변수나, 프로그램의 코드에 대한 메모리 공간은 각각 다르다. 

 프로그램은 크게 4가지 공간을 메모리에 할당받는다. 스택영역, 힙영역, 데이터영역, 코드영역으로 나뉜다.

스택영역

스택(stack)영역은 함수의 호출에서 얻게되는 지역변수나 매개변수가 저장되는 영역이다. 함수가 호출되면서 스택영역을 할당받으며, 함수와 함께 소멸한다. 이때, 스택영역에 저장되는 함수의 호출정보를 스택프레임(stack frame)이라고 말한다.

스택의 ADT를 살펴보면 push를 통해 데이터를 저장하고, pop으로 데이터를 인출하는 후입선출의 구조이다. 쉽게 생각하면 탄창과 같은 구조이기에 나중에 넣은 총알을 가장 먼저 발사하게 되는 구조이다.

힙영역

힙(heap)영역은 사용자가 직접 관리할 수 있고, "해야 하는"(must to) 메모리 영역이다. 사용자에 의해 메모리 공간이 동적으로 할당되고 해제된다.

데이터영역

데이터(data)영역은 프로그램의 전역변수와 정적(static)변수가 저장되는 영역이다. 프로그램의 시작에 할당이 되며 프로그램 종료시 소멸된다.

코드영역

코드(code)영역은 실행할 프로그램의 코드가 저장되는 영역으로 text영역이라고도 한다.

스택 포인터(stack pointer, sp)

 

CPU 안에는 스택에 데이터가 채워진 위치를 가리키는 레지스터인 스택 포인터(SP)를 갖고 있다. 즉, 스택 포인터란 레지스터중 하나를 의미한다. 스택포인터가 가리키는 곳까지가 데이터가 채워진 영역이고, 그 이후부터 스택 끝까지는 비어있는 영역이다.

스택에 새로운 항목이 추가되거나 스택에서 데이터가 제거되면, 스택 포인터의 값이 증가하거나 감소하는 식의 역할이다.

프레임 포인터(frame pointer, fp)

 

프레임 포인터 또한 레지스터이다. 함수 호출 이전의 스택포인터 위치를 기억하는 레지스터이다. 함수의 중첩시, 프레임 포인터의 값을 덮어쓸수 있기에 유의해야한다.

복사생성자 vs. 대입연산자

복사생성자는 객체의 복사가 이루어질때 생성되는 생성자이다.

대입연산자는 = 기호를 의미한다.

복사생성자와 대입연산자는 유사한 점이 많다. 복사 생성자의 대표적인 특성 세가지는 

  1. 정의하지 않으면 디폴트 복사생성자가 삽입된다.
  2. 디폴트 복사생성자는 얕은 복사를 진행한다. 
  3. 생성자 내에서 동적할당을 한다면, 깊은 복사가 필요하다면 직접 정의해야한다.

대입 연산자의 특징 세가지는 다음과 같다.

  1. 정의하지 않으면 디폴트 복사생성자가 삽입된다.
  2. 디폴트 복사생성자는 얕은 복사를 진행한다. 
  3. 생성자 내에서 동적할당을 한다면, 깊은 복사가 필요하다면 직접 정의해야한다.

차이점이 있다면, 호출되는 시점이다. 

복사생성자는 객체가 생성될때 호출되고, 대입연산자는 객체가 이미 생성된 후 호출된다.

 

 

오버로딩 vs. 오버라이딩

오버로딩과 오버라이딩은 이름뿐만 아니라 비슷한점이 많다. 정의부터 차근차근 살펴보면,

오버로딩은 함수를 여러개 정의하고, 매개변수의 유형이나 개수를 다르게하여 다양한 호출을 구분할수 있게 하는 것.

오버라이딩은 상속시, 상위 클래스가 갖고있는 함수를 하위클래스에서도 사용할 수 있도록 덮어쓰는 것 이다.

오버로딩의 경우, 함수 이름은 동일하고, 매개변수&타입은 다르며, 반환형은 상관없다.

오버라이딩의 경우, 함수 이름, 매개변수&타입 동일하며, 반환형 또한 동일해야한다.

 

 

 

 

'스터디 관련' 카테고리의 다른 글

CS스터디 02회차, ~06월 09일(목)  (0) 2022.06.09
CS스터디 01회차, ~06월 02일(목)  (0) 2022.06.02
1/6일 스터디 과제  (0) 2021.01.06
이번 스터디 과제,,  (0) 2020.12.31
소프트웨어 생명주기 6단계  (0) 2020.12.30

2.6 Defining Names for Constants

프로그램에 상수가 포함되어 있을 때는 종종 상수에 이름을 붙이는 것이 좋다. dweight.c나 dweight2.c 프로그램은 상수 166에 의존하는데, 그 의미는 프로그램을 읽는 다른 사람에게 모호할 수 있다. 매크로 함수를 이용하여, 이 상수의 이름을 다음과 같이 지을수 있다.

#define INCHES_PER_POUND 165

#define은 #include와 마찬가지로 전처리문이기에, 줄의 끝에는 세미콜론을 붙이지 않는다.

프로그램이 컴파일될 때, 전처리기는 각각의 매크로를 그것이 나타내는 값으로 대체한다. 예를 들어 다음 문장은

weight = (volume + INCHES_PER_POUND -1) / INCHES_PER_POUND;

 다음과 같이 

weight = (volume + 166 -1) / 166;

뒤의 문장을 쓴 것과 같은 효과가 나타난다. 매크로의 값은 expression(수식)으로 될 수 있다.

#define RECIPREOCAL_OF_PI (1.0f / 3.14159f)

만약 연산자를 포함한다면, 식을 괄호로 묶어주어야한다. 

매크로 이름에는 대문자만 사용했는데, 이것은 대다수의 C프로그래머들이 따르는 규칙이다. (필수사항은 아니다.)

그렇지만 관례가 있기에 이 규칙을 따르는 것이 좋을 것이다.

PROGRAM: Converting from Fahrenheit to Celsius

다음 프로그램은 사용자에게 화씨 온도를 입력하라는 메시지를 표시하고 동일한 섭씨 온도를 인쇄한다. 프로그램의 출력은 다음처럼 된다.

Enter Fahrenheit temperature: 212 //212는 사용자 입력값
Celsius equivalent: 100.0

이 프로그램은 정수가 아닌 온도도 허용해야하기에, 섭씨온도가 100이 아닌 100.0으로 표시된다. 

/* Convers a Fahrenheit temperature to Celsius */

#include <stdio.h>

#define FREEZING_PT 32.0f
#define SCALE_FACTOR (5.0f / 9.0f)

int main(void)
{
	float fahrenheit, celsius;
    
    printf("Enter Fahrenheit temperature: ");
    scanf("%f", &fahrenheit);
    
    celsius = (fahrenheit - FREEZING_PT) * SCALE_FACTOR;
    
    printf("Celsius equivalent: %.1f\n", celsius);
    
    return 0;
}

문장 celsius = (fahrenheit - FREEZING_PT) * SCALE_FACTOR;는 화씨 온도를 섭씨로 바꿔준다. FREEZING_PT가 32.0f를 의미하고, SCALE_FACTOR가 (5.0f / 9.0f) 를 의미하기에 컴파일러는 다음처럼 해석한다.

celsius = (fahrenheit - 32.0f) * (5.0f / 9.0f);

SCALE_FACTOR를 (5.0f / 9.0f)로 쓰는것은 중요한 사항이다. 5/9로 쓴다면 C가 두 정수가 나뉘는 것으로 생각하여 자른 결과를 준다. 5/9는 0이 될 것이고, 우리가 원하는 결과가 나오지 않는다.

printf의 호출은 섭씨를 기록하기 위함이다. %.1f를 사용하여 섭씨가 소숫점 뒤 한자리만 나오도록 표시했다.

이 페이지는 주기적으로 추가해 나갈 것이며, 평이 좋은 책을 기록할 예정이다.

C언어

  • C PROGRAMMING: A Modern Approach Second Edition, K.N.King, 원서, 832p 입문용으로 좋음.
  • K&R 입문용으로 쓰기는 살짝 어렵지만, C언어의 바이블로 불림

C++언어

  • 윤성우의 열혈C++, 윤성우, 한국어, 한국에서 매우 인기있는 책. 다른 C++ 책에 비해 그리 두껍지 않다.

컴퓨터 구조

  • Computer Systems: A Programmer's Perspective, Global Edition (3rd Edition), Randal E. Bryant / David R, O'Hallaron, 원서, 랩과제를 수행하면서 많은 지식을 배울수 있음
  •  

 

2.5 Reading Input

dweight.c 프로그램이 박스 단 하나의 dimensional weight를 계산하기 때문에, 특별히 유용한것은 아니다. 프로그램을 개선하려면 우리는 사용자가 dimension을 입력하도록 허용할 필요가 있다. 

입력을 갖기 위해서는, printf와 상응하는 C라이브러리의 scanf함수를 사용할 것이다. scanf의 f는 printf와 마찬가지로 "formatted"를 의미하며, 둘 모두 입력 또는 출력 데이터의 모양을 지정하기 위해 형식문자열(format string)을 사용해야한다. scanf는 printf가 어떻게 출력데이터를 표시할지 알아야하는 것처럼, 어떤 형식의 입력데이터가 들어올지 알아야한다. int 값을 읽기 위해 우리는 다음과 같이 scanf를 쓸 것이다.

scanf("%d", &i); /* reads an integer; stores into i */

%d 문자열은 scanf에게 정수를 나타내는 입력을 읽도록 지시하며, i는 scanf가 입력을 저장하도록 하는 int 변수이다. 현재는 &기호를 설명하기 어려우니, scanf를 사용할때 필수적으로 사용한다고 생각하자.(그러나 항상 그런것만은 아니다.)

float값을 읽으려면 약간 다른 scanf의 호출이 필요하다.

scanf("%f", &x); /* reads a float value; stores into x */

%f 는 float 변수인 경우에만 사용할 수 있다. 그러므로 x라는 변수는 float 변수임을 짐작할 수 있을 것이다 %f 문자열은 scanf가 float 형식의 입력값을 찾도록 지시한다. (소숫점을 가질 수도 있으나, 없어도 됨.)

 

PROGRAM: Computing the Dimensional Weight of a Box(Revisited)

다음은 유저가 수치를 직접 입력할 수 있는 향상된 버전의 dimensional weight 프로그램이다. 각각의 scanf 호출은 printf의 호출을 선행한다. 이렇게 하면 사용자는 입력 시기와 무엇을 입력할 지 알 수 있다.

/* dweight2.c 
   Computes the dimensional weight of a box from input provided by the user*/
  
 #include <stdio.h>
 
 int main(void)
 {
   int height, length, width, volume, weight;
   printf("Enter height of box: ");
   scanf("%d", &height);
   printf("Enter length of box: ");
   scanf("%d", &length);
   printf("Enter width of box: ");
   scanf("%d", &width);
   volume = height * length * width;
   weight = (volume + 165) / 166;
   
   printf("Volume (cubic inches): %d\n", volume);
   printf("Dimensional weight (pounds): %d\n", weight);
   
   return 0;
 }
 

프로그램은 다음과 같이 출력된다. (사용자 입력부분은 주석표시함)

Enter height of box: 8         //사용자입력:8
Enter length of box: 12        //사용자입력:12
Enter width of box: 10         //사용자입력:10
Volume (cubic inches): 960
Dimensional weight (pounds): 6

사용자에게 입력값(프롬프트)를 입력하라는 메세지는 일반적으로 개행문자로 끝나면 안된다. 사용자가 프롬프트 자체와 동일한 줄에 값을 입력하기를 희망하기 때문이다. 사용자가 엔터키를 누르면 커서가 자동으로 다음줄로 이동하므로, 현재 줄을 종료하기 위한 개행문자를 표시할 필요가 없다.

dweight2.c 프로그램에 문제가 있는데, 사용자가 숫자가 아닌 값을 입력하는 경우 프로그램은 제대로 작동하지 않는다. 이 부분은 3.2장에서 자세하게 다룰 것이다.

열혈 C++의 8장. 상속과 다형성을 복습하고 가상함수에 대해 익혀오는 과제가 있었다.

두개의 소스코드를 볼 수 있는데, FunctionVirtualOverride.cpp와 EmployeeManager4.cpp였다.

우선 가상함수에 대해서 간단히 짚고 넘어가보자.

가상함수란 virtual 키워드를 일반적인 함수 앞에 붙임으로 그 함수가 오버라이딩을 할 수 있게 해준다.

오버라이딩을 통해 한가지 기능을 다른 여러가지 기능으로 쓸수 있는 '다형성'을 만들어낼 수 있다.

또한, 가상함수가 선언되고 나면, 이 함수를 오버라이딩 하는 다른 함수는 virtual을 붙이지 않아도 가상함수가 된다.

/* FunctionVirtualOverride.cpp 
   열혈 C++ 347-348p           */
 
#include <iostream>
using namespace std;

class First //First 클래스 생성
{
public:
	virtual void MyFunc() { cout<<"FirstFunc"<<endl; } // FirstFunc을 출력하는 가상함수 MyFunc
};

class Second: public First //First를 상속받는 Second 클래스 생성
{
public:
	virtual void MyFunc() { cout<<"SecondFunc"<<endl; } //굳이 추가하지 않아도 가상함수가 되나 가독성을 위해 선언을 넣기도 한다.
};

class Third: public Second //Second를 상속받는 Third 클래스 생성
{
public:
	virtual void MyFunc() { cout<<"ThirdFunc"<<endl; }
};

int main(void)
{
	Third * tptr = new Third(); //Third 객체를 생성해서 Third형 포인터 변수로 참조
    Second * sptr = tptr; //Second형 포인터 변수로 참조
    First * fptr = sptr; //First형 포인터 변수로 참조
    
    fptr->MyFunc();  //포인터변수로 MyFunc 함수 호출
    sptr->MyFunc();
    tptr->MyFunc();
    delete tptr;
    return 0;
}

가상함수를 호출할때, 포인터의 자료형을 기반으로 호출대상이 결정되지 않고, 포인터 변수가 실제로 가리키는 객체를 참조하여 호출의 대상을 결정한다.

/* EmployeeManager4.cpp
   열혈C++ 349-351p	 */

#include <iostream>
#include <cstring>
using namespace std;

class Employee
{
private:
	char name[100];
public:
	Employee(char * name)
    {
    	strcpy(this->name, name);
    }
	void ShowYourName() const
    {
    	cout<<"name: "<<name<<endl;
    }
    virtual int GetPay() const
    {
		return 0;
    }
    virtual void ShowSalaryInfo() const
    {}
};

class PermanentWorker : public Employee
{
private:
	int salary; //월 급여
public:
	PermanentWorker
};
class TemporaryWorker : public Employee
{

};
class SalesWorker : public PermanentWorker
{

};

class EmployeeHandler
{
private:
	Employee* emplist[50];
    {}
    void AddEmployee(Employee* emp)
    {
    	emplist[empNum++]=emp;
    }
    void ShowAllSalaryInfo() const
    {
    	for(int i=0; i<empNum; i++)
        	empList[i]->ShowSalaryInfo();
    }
    void ShowTotalSalary() const
    {
    	int sum=0;
        for(int i=0;i<empNum;i++)
        	sum+=empList[i]->GetPay();
        
        cout<<"salary sum: "<<sum<<endl;
    }
    ~EmployeeHandler()
    {
    	for(int i=0; i<empNum; i++)
        	delete empList[i];
    }
};

int main(void)
{
	//직원관리를 목적으로 설계된 컨트롤 클래스의 객체생성
    EmployeeHandler handler;
    
    //정규직 등록
    handler.AddEmployee(new PermanentWorker("KIM",1000));
	handler.AddEmployee(new PermanentWorker("LEE",1500));
    
    //임시직 등록
    TemporaryWorker* alba = new TemporaryWorker("Jung", 700);
    alba->AddWorkTime(5);
    handler.AddEmployee(alba);
    
    //영업직 등록
    SalesWorker* seller = new SalesWorker("Hong", 1000, 0.1);
    seller->AddSalesResult(7000);
	handler.AddEmployee(seller);
    
    //이번 달에 지불해야 할 급여의 정보
    handler.ShowAllSalaryInfo();
    
    //이번 달에 지불해야 할 급여의 총합
    handler.ShowTotalSalary();
    return 0;
]

'스터디 관련' 카테고리의 다른 글

CS스터디 02회차, ~06월 09일(목)  (0) 2022.06.09
CS스터디 01회차, ~06월 02일(목)  (0) 2022.06.02
2/3(수) 과제  (0) 2021.02.03
이번 스터디 과제,,  (0) 2020.12.31
소프트웨어 생명주기 6단계  (0) 2020.12.30
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>

using namespace std;

class Person {
protected:
    int height;
    int weight;

    string gender;
    string personality;
    string dream;
public:
    Person() {}
    Person(int h, int w, string g) : height(h), weight(w), gender(g) {

    }

    void makePersonality(string personality) {
        this->personality = personality;

        cout << "내성격은" << this->personality << endl;
    }

    void makeDream(string dream) {
        this->dream = dream;

        cout << "내 꿈은" << this->dream << endl;
    }
    void showPerson() {
        cout << "안녕하세요! 저의 성별은" << gender << "이구요!" << endl;
        cout << "저의 키는 " << height << " ,저의 몸무게는" << weight << "입니다" << endl;
    }

};


class myClass : public Person {
private:
    char name[20];
    string music;

public:

    myClass() {};
    myClass(int h, int w, string g, const char* name) : Person(h, w, g) {
        strcpy(this->name, name);
    }
    void favoriteMusic(string music) {
        cout << "좋아하는 음악은 " << music << "입니다." << endl;
    }
    void showMyname() {
        cout << "제 이름은 " << name << "입니다." << endl;
    }
};

int main() {
    myClass hm(175, 67, "남자", "조현민");
    hm.showPerson();
    hm.showMyname();
    hm.makeDream(" 게임 개발자입니다.");
    hm.makePersonality(" 긍정적입니다.");
    hm.favoriteMusic("힙합");

}

'스터디 관련' 카테고리의 다른 글

CS스터디 02회차, ~06월 09일(목)  (0) 2022.06.09
CS스터디 01회차, ~06월 02일(목)  (0) 2022.06.02
2/3(수) 과제  (0) 2021.02.03
1/6일 스터디 과제  (0) 2021.01.06
소프트웨어 생명주기 6단계  (0) 2020.12.30

+ Recent posts