..

Search

32) 구조체의 활용

32) 구조체의 활용

구조체의 활용


함수와 구조체

C++에서는 함수를 호출할 때 전달되는 인수나, 함수가 종료될 때 반환되는 반환값으로도 구조체를 사용할 수 있습니다.

그 방식은 기본 타입과 완전히 같으며, 구조체를 가리키는 포인터나 구조체의 한 멤버 변수만을 사용할 수도 있습니다.

 

다음 예제는 구조체의 멤버 변수를 함수의 인수로 전달하는 예제입니다.

예제

struct Prop

{

    int savings;

    int loan;

};

 

int CalcProperty(int, int);

 

int main(void)

{

    int hong_prop;

    Prop hong = {10000000, 4000000};

 

    hong_prop = CalcProperty(hong.savings, hong.loan); // 구조체의 멤버 변수를 함수의 인수로 전달함

 

    cout << "홍길동의 재산은 적금 " << hong.savings << "원에 대출 " << hong.loan

        << "원을 제외한 총 " << hong_prop << "원입니다.";

    return 0;

}

 

int CalcProperty(int s, int l)

{

    return (s - l);

}

코딩연습 ▶

실행 결과

홍길동의 재산은 적금 10000000원에 대출 4000000원을 제외한 총 6000000원입니다.

 

위와 같이 구조체를 인수로 전달하는 방식은 함수가 원본 구조체의 복사본을 가지고 작업하므로 안전하다는 장점을 가집니다.

 

다음 예제는 함수의 인수로 구조체의 주소를 직접 전달하는 예제입니다.

예제

int CalcProperty(Prop*);

 

int main(void)

{

    ...

    hong_prop = CalcProperty(&hong); // 구조체의 주소를 함수의 인수로 전달함.

    ...

}

 

int CalcProperty(Prop* money)

{

    money->savings = 100; // 호출된 함수에서 원본 구조체의 데이터를 변경

    return (money->savings - money->loan);

}  

코딩연습 ▶

실행 결과

홍길동의 재산은 적금 100원에 대출 4000000원을 제외한 총 -3999900원입니다.

 

위와 같이 구조체를 가리키는 포인터를 인수로 전달하는 방식은 구조체의 복사본이 아닌 주소 하나만을 전달하므로 빠르다는 장점을 가집니다.

하지만 호출된 함수에서 원본 구조체에 직접 접근하므로, 원본 데이터의 보호 측면에서는 매우 위험합니다.

 

함수의 인수 전달 방법에 대한 더 자세한 사항은 C++ 인수 전달 방법 수업에서 확인할 수 있습니다.

 

C++ 인수 전달 방법 수업 확인 =>

 

따라서 다음 예제의 CalcProperty() 함수처럼 const 키워드를 사용하여 함수에 전달된 인수를 함수 내에서는 직접 수정할 수 없도록 하는 것이 좋습니다.

예제

Prop InitProperty(void);

int CalcProperty(const Prop*);

 

int main(void)

{

    ...

    hong = InitProperty();

    hong_prop = CalcProperty(&hong); // 구조체의 멤버 변수를 함수의 인수로 전달함

    ...

}

Prop InitProperty(void)

{

    Prop hong_prop = {10000000, 4000000};

    return hong_prop; // 구조체를 함수의 반환값으로 반환함.

}

 

int CalcProperty(const Prop* money) // const 키워드를 사용하여 구조체의 데이터를 직접 수정하는 것을 방지함.

{

    //money->savings = 100; // 호출된 함수에서 원본 구조체의 데이터를 변경

    return (money->savings - money->loan);

}

코딩연습 ▶

실행 결과

홍길동의 재산은 적금 10000000원에 대출 4000000원을 제외한 총 6000000원입니다.

 

위의 예제에서 CalcProperty() 함수 내의 주석 처리된 부분을 실행하여 원본 구조체에 대한 수정을 시도할 경우 C++ 컴파일러는 오류를 발생시킵니다.

 

또한, 위의 예제에서 InitProperty() 함수의 반환값으로 구조체를 반환합니다.

기본적으로 C++의 함수는 한 번에 하나의 데이터만을 반환할 수 있습니다.

하지만 이렇게 구조체를 사용하면 한 번에 여러 개의 데이터를 반환할 수 있게 됩니다.


중첩된 구조체

C++에서는 구조체를 정의할 때 멤버 변수로 또 다른 구조체를 포함할 수 있습니다.

예제

struct Name

{

    string first;

    string last;

};

 

struct Friends

{

    Name first_name;

    string address;

    string job;

};

코딩연습 ▶

실행 결과

서울시 강남구 역삼동

 

홍길동에게,

그동안 잘 지냈니? 아직도 학생이니?

다음에 꼭 한번 보자.

잘 지내.

 

위의 예제에서 Friends 구조체는 Name 구조체를 멤버 변수로 포함하고 있습니다.


구조체의 크기

구조체의 크기는 멤버 변수들의 크기에 따라 결정됩니다.

하지만 구조체의 크기가 언제나 멤버 변수들의 크기 총합과 일치하는 것은 아닙니다.

예제

struct TypeSize

{

    char a;

    int b;

    double c;

};

 

int main(void)

{

    cout << "구조체 TypeSize의 각 멤버의 크기는 다음과 같습니다." << endl;

    cout << sizeof(char) << ", " << sizeof(int) << ", " << sizeof(double) << endl;

 

    cout << "구조체 TypeSize의 크기는 다음과 같습니다." << endl;

    cout << sizeof(TypeSize);

    return 0;

}

코딩연습 ▶

실행 결과

구조체 TypeSize의 각 멤버의 크기는 다음과 같습니다.

1, 4, 8

 

구조체 TypeSize의 크기는 다음과 같습니다.

16

 

위의 예제에서 구조체 멤버 변수의 크기는 각각 1, 4, 8바이트입니다.

하지만 구조체의 크기는 멤버 변수들의 크기 총합인 13바이트가 아니라 16바이트가 됩니다.

 

구조체를 메모리에 할당할 때 컴파일러는 프로그램의 속도 향상을 위해 바이트 패딩(byte padding)이라는 규칙을 이용합니다.

구조체는 다양한 크기의 타입을 멤버 변수로 가질 수 있는 타입입니다.

하지만 컴파일러는 메모리의 접근을 쉽게 하려고 크기가 가장 큰 멤버 변수를 기준으로 모든 멤버 변수의 메모리 크기를 맞추게 됩니다.

이것을 바이트 패딩이라고 하며, 이때 추가되는 바이트를 패딩 바이트(padding byte)라고 합니다.

 

 

위의 예제에서는 크기가 가장 큰 double형 타입의 크기인 8바이트가 기준이 됩니다.

맨 처음 char형 멤버 변수를 위해 8바이트가 할당되며, 할당되는 1바이트를 제외한 7바이트가 남게 됩니다.

그다음 int형 멤버 변수는 남은 7바이트보다 작으므로, 그대로 7바이트 중 4바이트를 할당하고 3바이트가 남게 됩니다.

마지막 double형 멤버 변수는 8바이트인데 남은 공간은 3바이트뿐이므로 다시 8바이트를 할당받습니다.

따라서 이 구조체의 크기는 총 16바이트가 되며, 그중에서 패딩 바이트는 3바이트가 됩니다.


연습문제