![[C++] Struct 구조체 / 구조체 배열 / 구조체 배열 포인터](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FomuuM%2FbtsGLikSjJR%2FuCtCeMjdrimtTmpVHMMtvk%2Fimg.jpg)

구조체 (struct)
사용자가 하나 이상의 기본 타입을 가지고 새로운 자료형을 정의하는 사용자 정의 타입
(🔹 사용자 정의 타입 : int, char, double과 같은 자료형을 사용자가 임의로 만드는 것.)
- 모든 정보를 하나의 단위로 묶을 수 있는 형식이다.
- 서로 관련된 정보를 하나의 단위로 묶어서 저장할 수 있다.
- 하나의 구조체 안에 여러 종류의 데이터를 저장할 수 있다.
❓사용하는 이유
농구 선수에 관련된 모든 정보들을 저장한다고 했을 때, 이를 위해 각 이름, 연봉, 신장, 체중, 평균 득점 수, 자유투 성공률, 어시스트 수 등의 정보를 저장해야 할 때 구조체를 사용하여 관리하면 편하다.
💡 왜 배열은 적합하지 않을까?
배열은 여러 개의 값을 저장할 수는 있지만, 데이터형이 모두 같아야 하기 때문이다.
(🔹 Ex : 하나의 배열에 일부 원소에는 int형 값을 저장하고 다른 일부 원소에는 float형 값을 저장할 수 없다.)
구조체 선언 : 구조체 서술 (structure description)
struct 구조체명
{
타입 멤버변수1;
타입 멤버변수2;
....
};
1
2
3
4
5
|
struct Character // C 구조체에서 아무것도 붙이지 않으면 기본 public
{
int Hp; // 구조체 멤버
int Mp; // 구조체 멤버
};
|
cs |
- C#과는 다르게 중괄호 끝에 세미콜론(;)을 찍어준다.
- C/C++ 에서는 아무것도 붙이지 않으면 접근지정자가 기본 public이 된다.
구조체 데이터형의 변수 생성
1
2
3
4
5
|
Character player; // Character형의 구조체 변수
Character monster; // Character형의 구조체 변수
Character npc; // Character형의 구조체 변수
|
cs |
➡️ C 언어에서는 구조체 변수를 선언할 때 키워드 struct 써줘야 한다.
➡️ C++에서는 키워드 struct를 생략할 수 있다.
1
2
3
|
sturct Character player1; // C는 키워드 struct 요구
Character player; // C++은 키워드 struct를 요구하지 않음
|
cs |
구조체 멤버 접근
직접 접근(참조) 연산자: 멤버연산자 . (점)
개별적인 멤버에 접근하기 위해 사용한다.
(🔹배열 인덱스를 이용하여 배열 원소에 접근하는 것처럼, 멤버 이름을 사용하여 구조체의 멤버에 접근할 수 있음)
1
2
3
4
|
Character character;
character.Hp = 100;
character.Mp = 50;
printf("Hp = %d, Mp = %d\n", character.Hp, character.Mp);
|
cs |
구조체 포인터의 대한 접근방법
간접 참조 연산자: -> (화살표)
자기가 가지고있는 주소에 접근해서 멤버에 들어갈 수 있다. (주소만 가지고 있으면)
1
2
3
4
|
Character* character2 = new Character();
character2->Hp = 80;
character2->Mp = 60;
printf("Hp = %d, Mp = %d\n", character2->Hp, (*character2).Mp);
|
cs |
📝 구조체 사용 & 초기화하는 법 - 예제
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
32
33
34
35
36
37
|
#include <iostream>
using namespace std;
struct Character // 구조체 선언
{
char name[20];
float hp;
float damage;
};
int main()
{
// 초기화
Character player =
{
"Eile", // name 값
100.00, // hp 값
30.00 // damage 값
}; // player은 Character형의 구조체 변수이다
Character monster =
{
"Wisp",
50.00,
20.00
}; // Wisp은 Character형의 두 번째 변수이다
cout << "지금 플레이어의 이름은\n" << player.name;
cout << "이고 hp는 " << player.hp << "입니다\n";
// player.name은 player변수의 name 멤버이다
cout << player.name << "가 몬스터 " << monster.name << "에게 "
<< monster.damage << "만큼의 피해를 받아, 현재 체력이 "
<< player.hp - monster.damage << "이 되었습니다!";
return 0;
}
|
cs |
✅코드 분석✅
➡️ 14 Line C++에서는 ' = ' 표시는 선택사항이라서 생략할 수 있다.
➡️ 16 Line 한 줄에 모든 값들을 나타낼 수 있다. 그러나 반드시 초기화 값들을 콤마로 구분해줘야 한다.
⚠️ 공백을 가지는 중괄호는 각각의 멤버에 대하여 0으로 초기화한다 ⚠️
1
|
Character npc {};
|
cs |
구조체 외부선언 vs 내부선언
구조체는 선언을 두는 위치에 따라 사용할 수 있느냐 없느냐가 정해진다.
1️⃣ 외부 선언 : 선언 이후에 나오는 모든 함수들이 사용할 수 있다.
➡️ main() 함수의 앞에 선언 (외부선언 : external declaration)
2️⃣ 내부 선언 : 그 선언이 들어 있는 함수에서만 사용할 수 있다.
➡️ main() 함수의 안에 여는 중괄호 바로 뒤에 선언
구조체 배열
기본 데이터형의 배열을 만드는 것과 같다.
1
|
Character monster[100]; // Character형 구조체 100개의 배열
|
cs |
monster을 Character형의 배열로 만든다. 따라서 monster[0] 또는 monster[99]와 같은 배열 원소는 Character형 객체이다.
따라서 멤버 연산자를 사용할 수 있다.
1
2
|
cin >> monster[0].hp; // 첫 번째 구조체의 hp멤버에 입력
cout << monster[99].damage << endl; // 마지막 구조체의 damage 멤버를 출력
|
cs |
💡 여기서 monster 자체는 구조체가 아니라 배열이므로, monster.damage와 같은 표현은 아무런 의미가 없다.
구조체 배열을 초기화하는 방법
1
2
3
4
|
Character monster[2] = { // 구조체 배열을 초기화
{ "Goblin", 100, 30 }, // 첫 번째 배열 원소인 구조체
{ "Slime", 60, 50 } // 두 번째 배열 원소인 구조체
};
|
cs |
📝 구조체 배열 초기화 예제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <iostream>
using namespace std;
struct Character // 구조체 선언
{
char name[20];
float hp;
float damage;
};
int main()
{
Character monster[2] = { // 구조체 배열을 초기화
{ "Goblin", 100, 30 }, // 첫 번째 배열 원소인 구조체
{ "Slime", 60, 50 } // 두 번째 배열 원소인 구조체
};
cout << monster[0].name << "과 " << monster[1].name
<< "에게 동시에 뚜드려맞으면\n"
<< monster[0].damage + monster[1].damage
<< "의 데미지를 입습니다.\n";
return 0;
}
|
cs |
📝 구조체 배열 포인터 예제
1
2
3
4
5
6
7
8
9
10
|
// 배열 선언
Character arr[5];
// 배열 값 초기화
for (int i = 0; i < 5; i++)
arr[i].Hp = arr[i].Mp = 0;
// 출력
for (int i = 0; i < 5; i++)
printf("arr[%d] Hp = %d, Mp = %d\n", i, arr[i].Hp, arr[i].Mp);
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
arr[0].Hp = 10;
printf("arr[0] = %d\n", arr[0].Hp);
Character* pArr = arr;
pArr[1].Hp = 20; // = (*pArr + 1).Hp
printf("arr[1] = %d\n", arr[1].Hp);
(*(pArr + 2)).Hp = 30;
printf("arr[2] = %d\n", arr[2].Hp);
pArr->Hp = 40;
printf("arr[0] = %d\n", arr[0].Hp);
(arr + 3)->Hp = 50;
printf("arr[3] = %d\n", arr[3].Hp);
(pArr + 4)->Hp = 60;
printf("arr[4] = %d\n", arr[4].Hp);
|
cs |
✅코드 분석✅
➡️ 1 Line arr[0]은 Hp요소를 가지고 있어서 배열에 직접 접근하여 .(직접 접근 연산자)로 Hp에다가 10을 할당할 수 있다.
➡️ 4 Line Character형 포인터 변수 pArr을 생성하고 그 안에 arr의 주소값을 넣는다.
➡️ 5 Line pArr[1] 는 결국 (*pArr + 1)과 같기 때문에 가리키는 곳으로 가보면 arr[1]이 Hp를 가지고있어서 직접 접근하여 값을 줄 수 있다.
⚠️arr[1] = (*arr + 1)⚠️
1
2
3
4
5
|
arr[0].Hp = 10;
printf("arr[0] = %d\n", arr[0].Hp);
(*arr).Hp = 20;
printf("arr[0] = %d\n", (*arr).Hp);
|
cs |
➡️ 8 Line (*(pArr + 2)).Hp 부분에 괄호를 두 번 쓴 이유는, 직접 접근 연산자가 우선순위가 빠르기 때문에 괄호를 써서 *의 우선순위를 높이게 위함이다. / + 2는 주소번지를 [2]로 옮긴다는 이야기와 동일하다
➡️ 11 Line pArr은 arr의 주소값을 가지고 있기 때문에 간접 참조 연산자(->)를 사용하여 접근할 수 있다.
📝 구조체 배열 이중(더블) 포인터 예제
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
#include <stdio.h> // C style Header
#include <string> //C++ Sytle Heaer - STL
class Character // 구조체 선언
{
public:
int Id;
std::string Name;
private:
static int Number;
public:
static int Counting()
{
return ++Number;
}
};
int Character::Number = 0; // 외부에서 초기화를 시켜주어야 함
void SetCharacter(Character** character, std::string name)
{
Character* temp = new Character();
temp->Id = Character::Counting();
temp->Name = name;
*character = temp;
}
int main()
{
Character* swordMaster = nullptr;
SetCharacter(&swordMaster, "SwordMaster");
printf("%d, %s\n", swordMaster->Id, swordMaster->Name.c_str());
Character* magician = nullptr;
SetCharacter(&magician, "Magician");
printf("%d, %s\n", magician->Id, magician->Name.c_str());
Character* archer = nullptr;
SetCharacter(&archer, "Archer");
printf("%d, %s\n", archer->Id, archer->Name.c_str());
return 0;
}
|
//cs |
출처 및 참고: 강의 짱잘하시는 울 유니티 선생님 수업 / C++기초플러스

HyunZzang의 프로그래밍 공간 / 함께 공부해요!!
도움이 되셨다면 "좋아요❤️" 또는 "구독👍🏻" 부탁드립니다 :)