Notice
Recent Posts
Recent Comments
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

SYDev

C++ Chapter 03-1 : C++에서의 구조체 본문

Programming Lang/C++

C++ Chapter 03-1 : C++에서의 구조체

시데브 2023. 7. 12. 19:00

C++에서의 구조체 변수 선언

 구조체연관 있는 데이터를 묶을 수 있는 문법적 장치이다. 이런 구조체가 어떤 상황에 필요할까? 우리는 하나의 객체에 대하여 여러가지 변수를 선언해야할 때가 있다. 예를 들어서 하나의 자동차가 있다면 이에 대해서 소유주, 연료량, 현재속도 등의 정보가 필요하다. 이런 객체의 정보를 그룹화되지 않은 독립변수로 선언한다면 새로운 객체가 등장할 때마다 똑같은 정보를 매번 새로 만들어야 하는 불편함이 생긴다. 이런 불편함을 덜기 위해서 c++에서는 하나 이상의 변수를 묶어서 새로운 자료형을 정의하는 구조체(struct)를 이용할 수 있다.

 

 구조체는 다음과 같이 정의할 수 있다.

struct Car
{
    char gamerID[ID_LEN]; //소유자ID
    int fuelGauge; //연료량
    int curSpeed; //현재속도
};

 위 코드에서 gameID, fuelGauge, curSpeed와 같이 구조체 내부에 선언된 변수를 멤버(member) 또는 필드(field)라고 한다.

 

 추가적으로 구조체 변수의 선언은 다음과 같이 기본 자료형 변수의 선언방식과 같다.

Car basicCar;
Car simpleCar;

 

 그렇다면 구조체 개념을 이용한 다음 예제를 살펴보자.

#include <iostream>
using namespace std;

#define ID_LEN 20
#define MAX_SPD 200
#define FUEL_STEP 2
#define ACC_STEP 10
#define BRK_STEP 10

struct Car
{
    char gamerID[ID_LEN]; //소유자ID
    int fuelGauge; //연료량
    int curSpeed; //현재속도
};

void ShowCarState(const Car &car) //단순히 정보 출력만을 하는 함수이기 때문에 const 참조자를 매개변수로 선언
{
    cout<<"소유자 ID: "<<car.gamerID<<endl;
    cout<<"연료량: "<<car.fuelGauge<<"%"<<endl;
    cout<<"현재속도: "<<car.curSpeed<<"km/s"<<endl;
}

void Accel(Car &car)
{
    if(car.fuelGauge<=0)
        return;
    else
        car.fuelGauge-=FUEL_STEP;

    if(car.curSpeed+ACC_STEP>=MAX_SPD)
    {
        car.curSpeed=MAX_SPD;
        return;
    }

    car.curSpeed+=ACC_STEP;
}

void Break(Car &car)
{
    if(car.curSpeed<BRK_STEP)
    {
        car.curSpeed = 0;
        return;
    }

    car.curSpeed -=BRK_STEP;
}

int main(void)
{
    Car run99={"run99", 100, 0};
    Accel(run99);
    Accel(run99);
    ShowCarState(run99);
    Break(run99);
    ShowCarState(run99);

    Car sped77={"sped77",100, 0};
    Accel(sped77);
    Break(sped77);
    ShowCarState(sped77);

    return 0;
}
소유자 ID: run99
연료량: 96%
현재속도: 20km/s
소유자 ID: run99
연료량: 96%
현재속도: 10km/s
소유자 ID: sped77
연료량: 98%
현재속도: 0km/s

 

구조체 내부에 함수 선언

 위 예제에서 ShowCarState, Accel, Break와 같은 함수들은 구조체 Car에 사실상 종속되어있는 함수들이라고 할 수 있다. 그러나 지금은 전역함수의 형태를 띄고 있기 때문에 혼동하여 다른 곳에 사용할 수 있다. 그러므로 이번에는 해당 함수들을 구조체 안에 종속시켜보자. 

void ShowCarState()
{
    cout<<"소유자 ID: "<<gamerID<<endl;
    cout<<"연료량: "<<fuelGauge<<"%"<<endl;
    cout<<"현재속도: "<<curSpeed<<"km/s"<<endl;
}

 함수가 구조체 내부에서 정의된다면 위와 같은 형태로 바뀐다. 함수가 구조체 내부에 직접 삽입되었기 때문에 구조체 내에 선언된 변수에 직접 접근이 가능해졌다. 이러한 이유로 매개변수를 선언할 때나 구조체 내부의 변수를 사용할 때 구조체의 정보를 입력하지 않아도 된다.

 

Car run99={"run99", 100, 0};
run99.Accel();
run99.Accel();
run99.ShowCarState();
run99.Break();
run99.ShowCarState();

 구조체 외부에서의 함수 호출 또한 구조체 내부의 변수에 접근하는 방식과 동일하게 이루어진다. 

 

구조체 내부 enum 상수의 선언

 다음으로 예제 첫부분의 매크로 상수들에 주목해보자.

#define ID_LEN 20
#define MAX_SPD 200
#define FUEL_STEP 2
#define ACC_STEP 10
#define BRK_STEP 10

 이 상수들 역시 위 함수들과 마찬가지로 구조체 Car에게만 의미가 있는 상수들이다. 이런 경우에도 구조체 내부에 상수들을 포함시키는 것이 좋을 수 있다. 열거형 enum을 이용해 구조체 내에서만 유효한 상수를 정의해보자.

struct Car
{
    enum
    {
        ID_LEN = 20,
        MAX_SPD = 200,
        FUEL_STEP = 2,
        ACC_STEP = 10,
        BRK_STEP = 10    
    };
    
    .
    .
    .
};

  위와 같이 구조체 내부에서만 유효한 상수를 정의하는 것도 좋지만 이름공간을 이용하는 방법 또한 몇몇 구조체에서만 사용하는 상수를 선언할 때 좋을 수 있다.

namespace CAR_CONST
{
    enum
    {
        ID_LEN = 20,
        MAX_SPD = 200,
        FUEL_STEP = 2,
        ACC_STEP = 10,
        BRK_STEP = 10
    };
}

 이렇게 이름공간을 이용해서 해당 상수들을 CAR_CONST::변수이름 형태로 부를 수도 있다.

 

구조체 내부 함수의 선언&정의의 분리

 보통 프로그램을 분석할 때 함수의 기능만 파악하지, 함수의 세부 구현까지는 신경쓰지 않는다. 따라서 구조체 내부를 볼 때 정리된 함수의 종류와 기능이 한 눈에 들어오게 하기 위해서는 다음과 같이 함수의 정의를 선언과 분리해서 바깥으로 빼주는 것이 좋다. 

struct Car
{
    . . . . . .
    void ShowCarState(); 
    void Accel();
    . . . . . .
};

void Car::ShowCarState();
{
    . . . . .
}

void Car::Accel();
{
    . . . . .
}

 함수의 원형선언을 구조체 안에 두고, 정의를 구조체 외부로 빼냈기 때문에 해당 함수에 대한 설명을 주석으로 적절하게 남겨놓으면 좋다.

 

더보기

+ 사실 함수의 정의를 구조체 내부에 남겨놓는 경우도 있는데 이는 함수를 인라인 처리하라는 의미이다.

 

 그렇다면 지금까지의 내용을 모두 적용한 예제를 살펴보자.

#include <iostream>
using namespace std;

namespace CAR_CONST
{
    enum
    {
        ID_LEN = 20,
        MAX_SPD = 200,
        FUEL_STEP = 2,
        ACC_STEP = 10,
        BRK_STEP = 10
    };
}

struct Car
{
    char gamerID[CAR_CONST::ID_LEN]; //소유자ID
    int fuelGauge; //연료량
    int curSpeed; //현재속도

    void ShowCarState();
    void Accel();
    void Break();

};

void Car::ShowCarState()
{
    cout<<"소유자 ID: "<<gamerID<<endl;
    cout<<"연료량: "<<fuelGauge<<"%"<<endl;
    cout<<"현재속도: "<<curSpeed<<"km/s"<<endl;
}

void Car::Accel()
{
    if (fuelGauge <= 0)
        return;
    else
        fuelGauge -= CAR_CONST::FUEL_STEP;

    if (curSpeed + CAR_CONST::ACC_STEP >= CAR_CONST::MAX_SPD)
    {
        curSpeed = CAR_CONST::MAX_SPD;
        return;
    }

    curSpeed += CAR_CONST::ACC_STEP;
}

void Car::Break()
{
    if (curSpeed < CAR_CONST::BRK_STEP)
    {
        curSpeed = 0;
        return;
    }

    curSpeed -= CAR_CONST::BRK_STEP;
}

int main(void)
{
    Car run99={"run99", 100, 0};
    run99.Accel();
    run99.Accel();
    run99.ShowCarState();
    run99.Break();
    run99.ShowCarState();

    Car sped77={"sped77",100, 0};
    sped77.Accel();
    sped77.Break();
    sped77.ShowCarState();

    return 0;
}

 


참고자료

 

C++ 05.07 - 구조체, struct

05.07 - 구조체, struct 객체를 표현하기 위해 하나 이상의 변수가 필요한 프로그래밍 사례가 많이 있다. 예를 들어, 자신을 표현하기 위해 이름, 생일, 키, 몸무게 또는 자신에 대한 기타 특성을 저

boycoding.tistory.com

  • 윤성우, <윤성우의 열혈 C++ 프로그래밍>, 오렌지미디어, 2010.05.12