wn42
코딩이랑 이것저것
wn42
전체 방문자
오늘
어제
  • 분류 전체보기 (113)
    • 프로그래머스 (23)
      • LV1 (11)
      • LV2 (1)
      • LV3 (3)
      • 연습 (8)
    • 딥러닝 공부 (0)
      • 머신러닝&딥러닝 이론 (0)
    • 임베디드 (17)
      • Adventure Design (1)
      • 센서기반모바일로봇 (5)
      • ROS (9)
      • Google Coral (2)
    • C++ (38)
      • C++ 기초 (34)
      • 자료구조 및 알고리즘 (4)
    • Python (14)
      • 기본 파이썬 문법 (6)
      • Python 기초 (8)
    • 빅데이터 (9)
      • 빅데이터 첫걸음 시작하기(국비지원) (5)
      • 빅데이터 공부 (4)
    • 알고리즘 공부 (2)
      • 기본 알고리즘 (2)
    • 전자공학 (10)
      • 반도체 공정 (3)
      • 무선데이터통신 (7)
      • 반도체공학 (0)
    • C# (0)
      • C# 기본 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 빅데이터 첫걸음 시작하기
  • 빅데이터
  • 파이썬
  • Python
  • 데이터분석 인강
  • Queue
  • 딥러닝
  • 클래스
  • google coral
  • stl
  • numpy
  • ROS
  • 프로그래머스
  • 스택/큐
  • 노드
  • 스택
  • 내일배움카드
  • 조건문
  • 정렬
  • c++
  • 인스턴스
  • 소멸자
  • K디지털크레딧
  • 변수
  • 반복문
  • 큐
  • 상속
  • 패스트캠퍼스
  • 바이트디그리
  • 데이터분석

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
wn42
C++/C++ 기초

[C++] 구조체(Struct)

C++/C++ 기초

[C++] 구조체(Struct)

2022. 12. 28. 14:49

 구조체 

C/C++에서 구조화된 데이터를 처리할 때 사용

  • 하나 이상의 변수(같거나 다른 데이터형을 갖는)를 묶어 새로운 자료형을 정의하는 도구
  • 원시 자료형(int, float 등) 외에 새로운 데이터 타입을 직접 정의할 수 있게 함
  • C++에서는 기본 접근 제어자가 다른 것 말고는 클래스와 동일하다. (구조체-public, 클래스-private)

 

구조체 생성

구조체 정의

  • 구조체는 다음과 같이 정의한다.
  • 구조체를 정의할 때는 멤버 변수를 초기화할 수 없다.
// 정의 방법 1: 구조체만 정의
struct 구조체이름 {
/*멤버들*/
int age;
string name;
}; // 마지막에 무조건 ;(세미콜론) 붙여야 함
// 정의 방법 2: 구조체와 함께 구조체 변수를 정의
struct 구조체이름 {
/*멤버들*/
int age;
string name;
} 구조체변수이름;

 

구조체 변수 정의 및 멤버 변수 접근

  • 다음과 같이 구조체 변수를 정의한다.
struct 구조체명 구조체변수명
  • '.' (온점)을 이용하여 멤버 변수에 접근한다.
// 구조체명.구조체변수명
human.age = 19;

 

Ex) 간단한 구조체 예제

#include <iostream>
#include <string>
using namespace std;
struct human {
int age;
double height;
string name;
};
int main() {
// 1. 구조체 변수 정의 후 멤버 변수 초기화
struct human person1;
person1.age = 19;
person1.height = 182.3;
person1.name = "minwoo";
// 2. 구조체 변수 정의와 동시에 멤버 변수 초기화
struct human person2 = {20, 178.5, "hyunsoo"};
cout << person1.name << ", " << person1.age << ", " << person1.height << endl;
cout << person2.name << ", " << person2.age << ", " << person2.height << endl;
return 0;
}
minwoo, 19, 182.3
hyunsoo, 20, 178.5
  • 하나의 새로운 구조체를 정의하여 서로 다른 데이터형을 담아 정리할 수 있다.
  • 구조체 변수를 정의한 후 멤버 변수를 초기화하는 방식과, 정의와 동시에 초기화하는 방식이 있다.

 

Ex) 구조체 정의와 동시에 구조체 변수 정의 및 멤버 초기화

#include <iostream>
#include <string>
using namespace std;
struct human {
int age;
double height;
string name;
} person = { 23, 162.5, "Minji" }; // 구조체 변수 정의 및 멤버 초기화
int main() {
cout << person.name << ", " << person.age << ", " << person.height << endl;
return 0;
}
Minji, 23, 162.5
  • 구조체를 정의하면서 동시에 구조체 변수를 정의하고, 구조체 변수의 멤버를 초기화할 수 있다.

 

구조체 배열 만들기

  • 구조체에도 배열 자료구조를 사용할 수 있다.
#include <iostream>
#include <string>
using namespace std;
struct human {
int age;
double height;
string name;
};
int main() {
struct human person[2] = {
{19, 182.3, "minwoo"},
{20, 178.5, "hyunsoo"}
};
cout << person[0].name << ", " << person[0].age << ", " << person[0].height << endl;
cout << person[1].name << ", " << person[1].age << ", " << person[1].height << endl;
return 0;
}
minwoo, 19, 182.3
hyunsoo, 20, 178.5

 

구조체와 메모리

  • 구조체가 메모리에 어떤 식으로 저장되는지 확인한다.

 

Ex) 구조체 메모리 확인하기

#include <iostream>
#include <string>
using namespace std;
struct human {
int age;
double height;
string name;
};
int main() {
struct human person[2] = {
{19, 182.3, "minwoo"},
{20, 178.5, "hyunsoo"}
};
cout << "person[0]의 크기: " << sizeof(person[0]) << endl;
cout << "person[0]의 시작주소: " << &person[0] << endl;
cout << "person[0].age의 시작주소: " << &person[0].age << endl;
cout << "person[0].height의 시작주소: " << &person[0].height << endl;
cout << "person[0].name의 시작주소: " << &person[0].name << endl << endl;
cout << "person[1]의 크기: " << sizeof(person[1]) << endl;
cout << "person[1]의 시작주소: " << &person[1] << endl;
cout << "person[1].age의 시작주소: " << &person[1].age << endl;
cout << "person[1].height의 시작주소: " << &person[1].height << endl;
cout << "person[1].name의 시작주소: " << &person[1].name << endl;
return 0;
}
person[0]의 크기: 48
person[0]의 시작주소: 006FFB58
person[0].age의 시작주소: 006FFB58
person[0].height의 시작주소: 006FFB60
person[0].name의 시작주소: 006FFB68
person[1]의 크기: 48
person[1]의 시작주소: 006FFB88
person[1].age의 시작주소: 006FFB88
person[1].height의 시작주소: 006FFB90
person[1].name의 시작주소: 006FFB98
  • 4bytes(int) + 8bytes(double) + 28bytes(string) = 40bytes가 되어야 한다고 생각했지만, 총 크기는 48bytes이다.
  • 사실, 각 멤버 변수는 메모리 상에 1word 단위로 저장된다. ▶ 1word(32bit) - 4bytes, 1word(64bit) - 8bytes
  • 필자의 컴퓨터는 64bit이므로 1word가 8bytes 단위이다.
  • int와 double은 모두 1word 단위로 저장되어 8bytes만큼의 메모리를 할당받았다.
  • string은 기본 메모리 크기가 28bytes이지만, 1word의 배수가 되어야 하기에 32bytes만큼 할당되었다.
  • 따라서 구조체는 8bytes(int) + 8bytes(double) + 32bytes(string) = 48bytes의 메모리 크기를 갖는다.
  • 멤버변수끼리, 구조체끼리는 서로 순차적으로 연결되어 메모리 공간에 저장됨을 주소를 통해 알 수 있다.
  • 내용이 틀릴 수도 있으니 잘못된 부분은 댓글 부탁드립니다.

이에 관련된 자세한 내용은 아래 블로그에서 잘 정리하셨으니 참고바랍니다.

 

C언어 구조체의 메모리 사이즈(크기 계산)

* 구조체를 배우고 얼마 안되서, 구조체를 선언하여 그 크기를 계산해본적이 있다. 그런데...내가 상상했던...

blog.naver.com

 

 

구조체 포인터

  • 말 그대로 구조체를 가리키는 포인터를 말한다.
  • 구조체도 하나의 타입(형)이며, 메모리 공간에 저장되기 때문에 포인터로 시작주소를 가리킬 수 있다.

 

구조체 포인터 생성

#include <iostream>
using namespace std;
struct dummy {
int a, b;
};
int main() {
struct dummy d;
struct dummy *ptr; // 구조체 포인터 정의
ptr = &d; // 구조체 포인터이기 때문에 & 연산자 이용
(*ptr).a = 1;
(*ptr).b = 2;
cout << "d의 멤버 a: " << d.a << endl;
cout << "d의 멤버 b: " << d.b << endl;
cout << "ptr의 size: " << sizeof(ptr) << endl;
return 0;
}
d의 멤버 a: 1
d의 멤버 b: 2
ptr의 size: 4
  • 여기서 ptr은 struct dummy라는 형을 가리키는 포인터이다.
  • 구조체 포인터 ptr도 다른 모든 포인터와 동일하게 4byte의 메모리 공간을 차지한다.
  • 구조체는 변수이지, 배열이 아니다. ▶따라서 구조체 포인터를 만들 때, 구조체 변수의 이름이 아닌 & 연산자 + 구조체 변수 이름을 사용하여 구조체가 정의된 메모리 주소를 가져온다.

 

-> 연산자

  • 포인터의 경우 () 소괄호의 역할이 매우 크다. 다음 예시를 보자.

 

Ex) 포인터에 ( ) 소괄호를 붙이지 않는 경우

#include <iostream>
using namespace std;
struct dummy {
int a, b;
};
int main() {
struct dummy d;
struct dummy *ptr;
ptr = &d;
*ptr.a = 1; // 소괄호를 붙이지 않는 경우
(*ptr).b = 2;
cout << "d의 멤버 a: " << d.a << endl;
cout << "d의 멤버 b: " << d.b << endl;
return 0;
}

  • 소괄호를 넣지 않아서 오류가 발생하였다.
  • 이는 *(asterisk)과 .(period)연산자의 우선 순위에 의해 발생한 오류이다. 아래의 우선순위 표를 보자.

  • .(period)가 *(asterisk)보다 우선순위가 빠르다.
  • 따라서 *ptr.a는 *(ptr.a)의 순서로 처리된다. ▶ 여기서 ptr은 포인터로, 구조체가 아니기 때문에 멤버 변수 a를 가지고 있지 않다. 그러므로 a 멤버에 접근 시 오류가 발생한다.
  • 그렇기 때문에 구조체 포인터에서 ( ) 소괄호를 빠뜨리지 않고 꼭 적어야 한다.
  • 그런데 ( ) 소괄호를 계속 적는 것은 매우 귀찮은 일이다. ▶ 프로그래머들은 이 문제를 해결하기 위해 새로운 연산자를 개발했다. 바로 -> 연산자이다.

 

Ex) -> 연산자 이용하여 포인터로 멤버 변수에 접근하기

#include <iostream>
using namespace std;
struct dummy {
int a, b;
};
int main() {
struct dummy d;
struct dummy *ptr;
ptr = &d;
ptr->a = 1; // -> 연산자 이용하기
(*ptr).b = 2; // () 소괄호를 이용하는 기존 방식
cout << "d의 멤버 a: " << d.a << endl;
cout << "d의 멤버 b: " << d.b << endl;
return 0;
}
d의 멤버 a: 1
d의 멤버 b: 2
  • ptr->a = 1 이라는 표현은 (*ptr).a = 1 과 정확히 일치하는 문장이다.
  • 단순히 편의를 위해 -> 연산자가 도입되었으며, 이를 사용하면 귀찮게 ( ) 소괄호를 적을 필요가 없다.

 

구조체 포인터 연습

Ex) 포인터 멤버 연습 1

#include <iostream>
using namespace std;
struct dummy {
int* pointer;
};
int main() {
struct dummy d;
struct dummy* ptr; // 구조체 포인터 정의
int i = 0;
ptr = &d;
d.pointer = &i; // pointer 멤버가 포인터이므로, i의 주소값을 넘김. (*ptr).pointer = &i; 와 동일
*d.pointer = 3; // d의 멤버 pointer가 가리키는 변수 값을 3으로 변경. *(d.pointer) = 3; 와 동일
cout << "i의 값: " << i << endl;
*ptr->pointer = 4; // -> 연산자 이용하여 pointer 멤버가 가리키는 변수 값을 4로 변경
cout << "i의 값: " << i << endl;
return 0;
}
i의 값: 3
i의 값: 4
  • 멤버 변수에는 포인터를 포함시킬 수 있다.

 

Ex) 포인터 멤버 연습2 (Call-by-reference)

#include <iostream>
using namespace std;
int plus_ten(int*);
struct dummy {
int i;
};
int main() {
struct dummy d;
struct dummy* ptr; // 구조체 포인터 정의
ptr = &d;
ptr->i = 0; // 멤버 i 초기화
cout << "i의 값(함수 호출 전): " << ptr->i << endl;
plus_ten(&d.i); // 값 변경을 위해 구조체 멤버의 주소를 전달. &(d.i)와 동일
cout << "i의 값(함수 호출 후1): " << d.i << endl;
plus_ten(&ptr->i); // 값 변경을 위해 -> 연산자 이용. &(ptr->i)와 동일
cout << "i의 값(함수 호출 후2): " << ptr->i << endl;
return 0;
}
int plus_ten(int* num) {
*num += 10;
return 0;
}
i의 값(함수 호출 전): 0
i의 값(함수 호출 후1): 10
i의 값(함수 호출 후2): 20
  • 구조체 포인터를 이용하여 call-by-reference를 구현한 예제이다.
  • 연산자의 우선순위를 잘 따져야 한다. ▶ &d.i → &(d.i)

 

 

구조체 복사하기

  • 구조체는 대입 연산을 통해 간단히 복사가 가능하다.
#include <iostream>
using namespace std;
struct dummy {
int i;
string str;
};
int main() {
struct dummy a, b;
a.i = 10;
a.str = "Hello!";
b = a; // 대입하여 복사하기
cout << "a의 멤버 i: " << a.i << endl;
cout << "a의 멤버 str: " << a.str << endl;
cout << "b의 멤버 i: " << b.i << endl;
cout << "b의 멤버 str: " << b.str << endl;
return 0;
}
a의 멤버 i: 10
a의 멤버 str: Hello!
b의 멤버 i: 10
b의 멤버 str: Hello!

 

 

구조체 매개변수

  • 구조체를 인자(매개변수)로 전달할 수 있다.
  • 구조체를 인자로 전달할 때 call-by-reference가 이루어져야 함을 유의한다.

 

구조체 인자 전달하기

#include <iostream>
using namespace std;
int set_struct(struct dummy*, int, string);
struct dummy {
int i;
string str;
};
int main() {
struct dummy a;
set_struct(&a, 10, "Hello!!");
cout << "a의 멤버 i: " << a.i << endl;
cout << "a의 멤버 str: " << a.str << endl;
return 0;
}
int set_struct(struct dummy *sr, int i, string str) {
sr->i = i;
sr->str = str;
return 0;
}
a의 멤버 i: 10
a의 멤버 str: Hello!!
  • 구조체 변수 a의 주소를 인자로 전달함으로써 구조체 멤버에 접근하여 값을 초기화할 수 있다.
  • 이때 함수 set_struct의 매개변수 sr은 구조체 포인터이며, 절대 구조체가 아니다. ▶ 단지 sr은 구조체 변수 a가 저장된 메모리의 시작주소를 담는다.

 

 

구조체 안의 구조체

  • 구조체는 구조체를 멤버로 가질 수 있다.
#include <iostream>
using namespace std;
struct profiles {
int gradeNum;
int classNum;
int studentNum;
string name;
};
struct school {
struct profiles data;
string schoolName;
};
int main() {
struct school High;
High.schoolName = "Seoul";
High.data.gradeNum = 2;
High.data.classNum = 7;
High.data.studentNum = 17;
High.data.name = "minji";
cout << "학교이름: " << High.schoolName << " High School" << endl;
cout << "학년: " << High.data.gradeNum << endl;
cout << "반: " << High.data.classNum << endl;
cout << "이름: " << High.data.name << endl;
cout << "번호: " << High.data.studentNum << endl;
return 0;
}
학교이름: Seoul High School
학년: 2
반: 7
이름: minji
번호: 17
  • 구조체 또한 int, float와 같은 하나의 형(타입)이기 때문에 구조체가 구조체를 멤버로 가질 수 있는 것은 당연하다.
  • 연산자 우선순위에 의해 High.data.name은 (High.data).name로 처리된다. ▶ High의 멤버 data의 멤버 name

 

 

구조체 반환하기

  • 구조체는 하나의 타입(형)이기 때문에 반환(return)이 가능하다.
  • 아래는 구조체를 반환하는 함수를 구현한 예제이다.
#include <iostream>
using namespace std;
struct dummy func(int);
struct dummy {
int a;
};
int main() {
struct dummy d;
d = func(10); // return한 구조체를 복사
cout << "d의 멤버 a: " << d.a << endl;
return 0;
}
struct dummy func(int i) {
struct dummy A;
A.a = i;
return A;
}
d의 멤버 a: 10

 

 

구조체 안에 함수 넣기

  • 구조체 안에 함수를 넣고, 함수에 구조체 멤버 변수들을 활용할 수 있다.
  • 구조체 안의 들어있는 함수 또한 멤버이며, 이를 멤버 함수 또는 멤버 메서드라고 한다.
#include <iostream>
using namespace std;
struct dummy {
int a, b;
// 멤버 함수(멤버 메서드)
int mul() {
return a * b; // 멤버 변수 사용 가능
}
};
int main() {
struct dummy d = {5, 10};
cout << d.a << " x " << d.b << " = " << d.mul() << endl;
return 0;
}
5 x 10 = 50

 

  •  구조체 
  • 구조체 생성
  • 구조체 포인터
  • 구조체 복사하기
  • 구조체 매개변수
  • 구조체 안의 구조체
  • 구조체 반환하기
  • 구조체 안에 함수 넣기
'C++/C++ 기초' 카테고리의 다른 글
  • [C++] 열거형(Enum)
  • [C++] 공용체(Union)
  • [C++] typedef
  • [C++] 디버깅(Debugging)
wn42
wn42
코딩이랑 이것저것 하는 블로그

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.