A. 구조체
1. 구조체의 기본
a. 구조체란?
🌟 사용자가 C++언어의 기본 타입을 가지고 새롭게 정의할 수 있는 사용자 정의 타입
= 사용자 정의 자료형이라고 부름
배열이 같은 타입의 변수 집합이라면, 구조체는 다양한 타입의 변수 집합을 하나의 타입으로 나타낸 것
👉 이때 구조체를 구성하는 변수(함수)를 구조체의 맴버 또는 맴버변수라고 함
타입일 뿐만 아니라, 클래스의 기초가 됨
b. 구조체의 특징
기본 타입만으로는 나타낼 수 없는 복잡한 데이터를 표현할 수 있음
또한 함수 리턴값으로 구조체를 사용하면 여러 개의 데이터를 한 번에 반환할 수 있음 (함수는 원래 하나의 값만 가능)
c. 구조체의 정의와 선언
📘 구조체 타입 정의
struct 구조체이름 //struct 키워드 : 구조체의 시작을 알림
{
멤버변수1의타입 멤버변수1의이름;
멤버변수2의타입 멤버변수2의이름;
...
}; //; : 구조체의 정의를 종료한다는 의미
📘 구조체 변수 선언
struct 구조체이름 구조체변수이름;
⏳ 예제
struct Book web_book;
//C++에서는 구조체 변수를 선언할 때 struct 키워드를 생략가능
🎨 도식화
👉 구조체의 정의와 선언을 동시에 할수도 있음
📘 문법
struct 구조체이름
{
멤버변수1의타입 멤버변수1의이름;
멤버변수2의타입 멤버변수2의이름;
...
} 구조체변수이름;
🤓 예제
struct book
{
char title[30];
char author[30];
int price;
} my_book;
d. 구조체 멤버로의 접근방법
🌟 멤버 참조 연산자(.)를 사용
구조체의 주소값과 구조체의 첫 번째 멤버 변수의 주소값은 언제나 같음
📘 문법
구조체변수이름.멤버변수이름
🤓 예제
my_book.author
e. 구조체 변수의 초기화
🌟 중괄호({})를 사용한 초기화 리스트를 사용하여 초기화
- 멤버 변수가 정의된 순서에 따라 차례대로 초깃값이 설정
- 초기화하지 않은 멤버 변수는 0으로 초기화
- 구조체 변수를 초기화 할때 = 생략 가능
- 💥 narrowing 지원하지 않음
📘 문법
구조체변수이름 = {멤버변수1의초깃값, 멤버변수2의초깃값, ...};
//ex) web_book = {"HTML과 CSS", "홍길동", 28000};
🤓 예제 : 배열의 초기화 방법을 사용한 초기화
#include <iostream>
#include <string>
using namespace std;
struct book
{
string title;
string author;
int price;
};
int main(void)
{
book web_book = {"HTML과 CSS", "홍길동", 28000};
book java_book = {"Java language", "이순신"};
cout << "첫 번째 책의 제목은 " << web_book.title << "이고, 저자는 " << web_book.author
<< "이며, 가격은 " << web_book.price << "원입니다." << endl;
cout << "두 번째 책의 제목은 " << java_book.title << "이고, 저자는 " << java_book.author
<< "이며, 가격은 " << java_book.price << "원입니다.";
return 0;
}
✨ 실행결과
첫 번째 책의 제목은 HTML과 CSS이고, 저자는 홍길동이며, 가격은 28000원입니다.
두 번째 책의 제목은 Java language이고, 저자는 이순신이며, 가격은 0원입니다.
B. 구조체의 활용
1. 함수와 구조체
함수의 매개변수나, 반환값으로 구조체를 사용할 수 있음
사용 방식은 기본 타입과 완전히 같고, 구조체를 가리키는 포인터나 멤버 변수만을 사용할 수도 있음
a. 매개변수 : 구조체를 인수로 전달하기
원본 구조체의 복사본을 가지고 작업하면 데이터가 안전해짐
⏳ 예제 : 구조체의 멤버 변수를 함수의 인수로 전달
#include <iostream>
using namespace std;
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원입니다.
b. 매개변수 : 구조체의 주소를 인수로 전달하기
구조체의 복사본이 아닌 주소 하나만을 전달하므로 빠르다는 장점
💥 하지만 원본 데이터 보호 측면에서는 위험함
⏳ 예제 : 함수의 인수로 구조체의 주소를 직접 전달
#include <iostream>
using namespace std;
struct Prop
{
int savings;
int loan;
};
int CalcProperty(Prop*);
int main(void)
{
int hong_prop;
Prop hong = {10000000, 4000000};
hong_prop = CalcProperty(&hong); // 구조체의 주소를 함수의 인수로 전달함.
cout << "홍길동의 재산은 적금 " << hong.savings << "원에 대출 " << hong.loan
<< "원을 제외한 총 " << hong_prop << "원입니다.";
return 0;
}
int CalcProperty(Prop* money)
{
money->savings = 100; // 호출된 함수에서 원본 구조체의 데이터를 변경
return (money->savings - money->loan);
}
✨ 실행결과
홍길동의 재산은 적금 100원에 대출 4000000원을 제외한 총 -3999900원입니다.
👉 위와 같이 데이터가 수정되어버려서 const 키워드를 활용해야 함
⏳ 예제 : const 키워드를 사용해 수정을 방지
#include <iostream>
using namespace std;
struct Prop
{
int savings;
int loan;
};
int CalcProperty(const Prop*);
int main(void)
{
int hong_prop;
Prop hong = {10000000, 4000000};
hong_prop = CalcProperty(&hong); // 구조체의 멤버 변수를 함수의 인수로 전달함
cout << "홍길동의 재산은 적금 " << hong.savings << "원에 대출 " << hong.loan
<< "원을 제외한 총 " << hong_prop << "원입니다.";
return 0;
}
int CalcProperty(const Prop* money) // const 키워드를 사용하여 구조체의 데이터를 직접 수정하는 것을 방지함.
{
//원본 구조체에 대한 수정을 시도할 경우 C++ 컴파일러는 오류를 발생
//money->savings = 100; // 호출된 함수에서 원본 구조체의 데이터를 변경
return (money->savings - money->loan);
}
✨ 실행결과
홍길동의 재산은 적금 10000000원에 대출 4000000원을 제외한 총 6000000원입니다.
💥 주석처리된 부분을 실행하면 C++ 컴파일러는 오류를 발생
c. 반환값 : 구조체
구조체를 사용하면 한 번에 여러개의 데이터를 반환할 수 있게 함
⏳ 예제 : 함수의 반환값으로 구조체를 반환
...
int main(void)
{
Prop hong;
int hong_prop;
hong = InitProperty();
...
}
Prop InitProperty(void)
{
Prop hong_prop = {10000000, 4000000};
return hong_prop; // 구조체를 함수의 반환값으로 반환함.
}
...
2. 중첩된 구조체
a. 구조체를 가지는 구조체
🌟 구조체를 정의할 때 멤버 변수로 또 다른 구조체를 포함할 수 있음
⏳ 예제 : Address 구조체를 중첩하는 User 구조체
#include <iostream>
#include <string>
// 주소 정보를 저장하는 Address 구조체
struct Address {
std::string street;
std::string city;
std::string zipCode;
};
// 사용자 정보를 저장하는 User 구조체 (주소 정보 포함)
struct User {
std::string username;
std::string email;
Address address; // 중첩된 Address 구조체
};
int main() {
// 사용자 정보 초기화
User user;
user.username = "johndoe";
user.email = "johndoe@example.com";
user.address.street = "123 Main St";
user.address.city = "Anytown";
user.address.zipCode = "12345";
// 정보 출력
std::cout << "Username: " << user.username << std::endl;
std::cout << "Email: " << user.email << std::endl;
std::cout << "Address: " << user.address.street << ", " << user.address.city << ", " << user.address.zipCode << std::endl;
return 0;
}
✨ 실행결과
Username: johndoe
Email: johndoe@example.com
Address: 123 Main St, Anytown, 12345
3. 구조체의 크기
a. 구조체의 크기 계산하기
🌟 멤버 변수들의 크기에 따라 결정
💥 하지만 구조체의 크기가 언제나 멤버 변수들의 크기 총합과 일치하는 것은 아님
⏳ 예제 : 구조체의 크기 계산하기
#include <iostream>
using namespace std;
struct TypeSize
{
char a;
int b;
double c;
};
int main(void)
{
cout << "구조체 TypeSize의 각 멤버의 크기는 다음과 같습니다." << endl;
cout << sizeof(char) << ", " << sizeof(int) << ", " << sizeof(double) << endl << endl;
cout << "구조체 TypeSize의 크기는 다음과 같습니다." << endl;
cout << sizeof(TypeSize);
return 0;
}
✨ 실행결과
구조체 TypeSize의 각 멤버의 크기는 다음과 같습니다.
1, 4, 8
구조체 TypeSize의 크기는 다음과 같습니다.
16 //위와 크기가 일치하지 않음
b. 바이트 패딩(byte padding)
🌟 구조체를 메모리에 할당할 때 컴파일러가 프로그램의 속도 향상을 위해 사용하는 규칙
구조체는 다양한 타입을 멤버 변수로 가질 수 있어서
컴파일러는 메모리의 접근을 쉽게 하기 위해 가장 큰 멤버 변수를 기준으로 메모리 크기를 맞추게 됨
이걸 바이트 패딩이라고 하고, 이때 추가되는 바이트를 패딩 바이트(padding byte)라고 함
- 가장 큰 double 자료형으로 8byte 할당
- char, int형 메모리 처리
- double형 메모리 처리할 공간이 없으므로 8byte 추가 할당
- 최종적으로 16byte 메모리가 할당됨 (3 패딩 바이트)
'프로그래밍 언어 > C++' 카테고리의 다른 글
C++ 범위 : 유효범위와 연결 (0) | 2023.09.13 |
---|---|
[자료형(data type)] C++ 파생형 공용체와 열거체 총정리 (0) | 2023.09.13 |
[게임 프로그래머 입문 올인원] 객체지향 : static과 싱글톤 (33강) (0) | 2023.09.12 |
[게임 프로그래머 입문 올인원] 객체지향 : 연산자 오버로딩 (32강) (0) | 2023.09.12 |
[게임 프로그래머 입문 올인원] 객체지향 : 멤버 변수 초기화 (31강) (0) | 2023.09.11 |