[C++] 구조체

꿈별·2022년 11월 22일
0

C++

목록 보기
7/27

✔구조체

  • 하나 이상의 변수를 그룹지어 사용자 정의 자료형으로 새롭게 정의하는 것으로,
    기본 타입만으로는 나타낼 수 없는 복잡한 데이터를 표현할 수 있다.

    • 배열 ) 같은 타입의 변수 집합
    • 구조체 ) 다양한 타입의 변수 집합을 하나의 타입으로 나타낸 것
      -> 이때 구조체를 구성하는 변수 : 멤버 또는 필드
  • C++ 구조체는 변수뿐만 아니라 함수까지도 멤버 변수로 가질 수 있다.

💡 기본적으로 C++ 함수는 한 번에 하나의 데이터만을 반환할 수 있다.
하지만 구조체를 사용하면 한 번에 여러 개의 데이터를 반환할 수 있다.

구조체 선언

❗ 구조체 선언의 끝에 세미콜론을 꼭 써야 한다.

[구조체 선언 및 정의]
struct 구조체이름
{
	멤버변수타입 멤버변수이름;
};

ex)
struct CafeMenu
{
	string name;
    string sugar;
    int price;
};
[구조체 변수 선언]
struct 구조체이름 구조체변수이름;
ex)
struct CafeMenu coffee;
혹은
CafeMenu coffee;

💡 C와 달리 C++은 구조체 변수 선언 시 struct 키워드 생략 가능,
But 코드가 C, C++에서 범용적으로 사용되도록 보통 C 문법을 기준으로 코드를 작성한다.


typedef 키워드

  • 이미 존재하는 타입에 새 이름을 붙일 때 사용
  • C는 구조체 변수를 사용/선언할 때 매번 struct 키워드를 붙여서 해당 변수가 구조체임을 알려야 한다.
    -> 번거롭기 때문에 typedef 키워드를 사용하여 구조체에 새로운 이름을 선언해 준다.
[키워드X]
//[struct 구조체이름]이 세트로 사용됨
sturct 구조체이름
{
	멤버변수타입 멤버변수이름;
};

struct 구조체이름 멤버변수이름;

[키워드O] 
// 구조체 정의와 typedef 선언을 동시에 하면 구조체이름 생략 가능
typedef sturct (구조체이름)
{
	멤버변수타입 멤버변수이름;
} 구조체새이름;

구조체새이름 멤버변수이름;

구조체 멤버 접근

  • 구조체에서 구조체 멤버로 접근하려고 할 때는 멤버 선택 연산자(.)를 사용한다.
[문법]
구조체변수이름.멤버변수이름
ex)
coffee.price

구조체 변수 초기화

  • C++에서 구조체 변수는 중괄호({})를 사용한 초기화 리스트를 사용해 초기화한다.
[문법]
구조체변수이름 = {멤버변수1의초깃값, 멤버변수2의초깃값, ...};
ex)
coffee = {"연유라떼", "30g", 6000};

👉 멤버 변수가 정의된 순서에 따라 차례대로 초깃값이 설정되며,
초기값이 포함되지 않은 멤버는 기본값으로 초기화된다.
초기값을 미리 지정해두지 않으면 0으로 초기화한다.

✔구조체 활용

함수와 구조체

  • 구조체를 멤버와 함께 함수에 전달할 수 있다.
    -> 함수 종료시 반환되는 반환값, 함수 호출시 전달되는 인수
  • 함수는 구조체를 반환함으로써 여러 변수를 반환할 수 있다.

-> 구조체의 멤버 변수를 함수의 인수로 전달

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);
}

-> 함수의 인수로 구조체 직접 전달

int CalcProperty(Prop*);
int main(void)
{
    ...
    hong_prop = CalcProperty(&hong); // 구조체의 주소를 함수의 인수로 전달함.
    ...
}
int CalcProperty(Prop* money)
{
    money->savings = 100; // 호출된 함수에서 원본 구조체의 데이터를 변경
    return (money->savings - money->loan);
}  

👉 위와 같이 구조체를 가리키는 포인터를 인수로 전달하는 방식은 구조체의 복사본이 아닌 주소 하나만을 전달하므로 빠르다는 장점을 가진다.
❗ but 원본 데이터 보호 측면에서 매우 위험


const 키워드 - 구조체 데이터 보호 문제 개선

  • 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);
}

중첩된 구조체

  • 구조체는 다른 구조체를 포함할 수 있다.
struct Book
{
	string name;
    int price;
    string author;
};

struct Library
{
	Book myBook;
    int numOfBook;
};

Library ycLibrary

👉 아래와 같이 중첩된 구조체에 대해 중첩된 초기화 목록을 사용할 수 있다.
ex) Library ycLibrary = {{"책이름", 12900, "저자명"}, 1};
👉 위 코드에서 myBook의 멤버변수 값을 알고 싶으면 멤버 선택 연산자(.)를 두 번 사용하면 된다.

std::cout << ycLibrary.myBook.name

👉 yclibrary에서 myBook을 선택하고 그 안에서 name을 선택

구조체 크기와 정렬

  • 구조체의 크기는 멤버 변수들의 크기에 따라 결정되기 때문에 일반적으로 모든 멤버의 크기를 합한 값이다.
    -> but 구조체의 크기가 언제나 멤버 변수들의 크기 총합과 일치하진 않음
struct TypeSize
{
    char a;	//1byte
    int b;	//4byte
    double c;	//8byte
	//but!! 구조체 크기 : 16byte
};
  • 패딩(바이트 패딩) : 구조체를 메모리에 할당할 때 프로그램 속도 향상을 위해 컴파일러가 구조에 간격을 추가하는 것.
    -> 구조체는 다양한 크기의 타입을 멤버 변수로 가질 수 있지만,
    컴파일러는 메모리 접근을 쉽게 하기 위해 크기가 가장 큰 멤버 변수를 기준으로 모든 멤버 변수의 메모리 크기를 맞추게 된다. 이때 추가되는 바이트를 패딩 바이트라고 한다.

공용체(union)

  • union 키워드를 사용해 선언하며, 모든 면에서 구조체와 같다.
    -> 차이점: 모든 멤버 변수가 하나의 메모리 공간을 공유함
  • 모든 멤버 변수가 같은 메모리를 공유하기 때문에 공용체는 한 번에 하나의 멤버 변수만 사용할 수 있다.
  • 장점 ) 메모리 크기가 제한되어 있거나 메모리를 절약할 때 유용함
  • 단점 ) 하나의 데이터 사용 후 데이터를 변경할 경우 원래의 데이터를 잃는다.
  • 순서가 불규칙적이고, 미리 알 수 없는 다양한 타입의 데이터를 저장할 수 있도록 설계된 타입
  • 크기가 가장 큰 멤버 변수의 크기만큼 메모리를 할당받고, 나머지 변수들은 앞에서부터 메모리를 공유한다.
    -> 따라서 공용체 배열을 사용하면, 같은 크기로 구성된 배열 요소에 다양한 크기의 데이터를 저장할 수 있다.

❗ 공용체에 저장된 값의 의미는 값을 저장할 때 공용체의 어떤 멤버 변수를 사용했는지에 따라 달리 해석된다.
또한 공용체 중 하나의 멤버 변수만 초기화해도 나머지 멤버 변수도 그 값을 동시에 공유하게 된다.


열거형(enum)

  • enum 키워드를 사용해 선언하며, 각 열거자는 쉼표(,)로 구분한다. enum 자체는 세미콜론(;)으로 끝나야 한다.
  • 새로운 타입을 선언하면서 동시에 그 타입이 가질 수 있는 정수형 상숫값도 같이 명시한다.
  • 장점 ) 프로그램 가독성이 높아지고, 변수가 지니는 값에 의미를 부여할 수 있다.
  • 열거형을 정의해도 메모리가 할당되지 않고, 열거된 유형의 변수가 정의되면 해당 변수의 메모리가 할당된다.
  • 상숫값을 따로 명시하지 않으면 0부터 시작되며, 그 다음바로 앞의 상숫값보다 1만큼 증가되며 정의된다.
  • 열거형은 고유한 데이터 타입이므로 다른 열거형의 열거자를 저장할 수 없다.

[참고]
http://www.tcpschool.com/cpp/cpp_struct_intro
http://www.tcpschool.com/c/c_struct_intro
https://boycoding.tistory.com/183
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=imbin_&logNo=221330417695
https://min-zero.tistory.com/entry/C-%EA%B8%B0%EB%B3%B8-%EA%B3%B5%EB%B6%80%EC%A0%95%EB%A6%AC-10-%EA%B3%B5%EC%9A%A9%EC%B2%B4union-%EC%97%B4%EA%B1%B0%EC%B2%B4enum
https://youtu.be/Nrtg_YSqwu4

0개의 댓글