[C++] 구조체(Structure)[C++ vs. C], 구조체 포인터

2024. 3. 8. 21:38Programming Language/C++

아래 링크 클릭 시 해당 본문으로 이동

구조체

구조체 포인터


구조체(Structure) - C++ vs. C

1. C++ 문법

 사용자 정의 자료형(UDDT : User Defined Data Type)이라고도 한다.

내 맘대로 자료형을 만드는 것 (나만의 자료형)

기본 문법이 아니기 때문에 내가 짠 코드에서만 적용된다.

언어에서 기본으로 제공해 주는 자료형 외에 내 방식대로 새로운 자료형을 만들고 싶을 때 사용한다.

// typedef : 타입 재정의
typedef struct 구조체명
{
    구조체 멤버;  // 멤버 : 구성 요소
} 구조체변수명;  // 세미콜론 꼭 쓰기!

 

구조체도 모듈화가 가능하다.

더 큰 자료형 안에 내가 만든 구조체가 그것의 부분으로 들어가서 점점 확장해 나갈 수 있다.

typedef struct _tagMYST
{
	int a;
    float b;
} MYST;

typedef struct _tagBig
{
	MYST m;  // 구조체 변수 MYST의 멤버 m을 _tagBig 안에서 선언했다.
    int d;
    char e;
} BIG;

 

※ 구조체 안에 변수를 선언

// MYST => int형 + float형
typedef struct _tagMYST
{
	int a;  // int 파트 이름 : a
    float b;  // float 파트 이름 : b
} MYST;

 

'int형 변수 a'처럼 변수를 선언한 것이 아니다.

단지 이름을 부여한 것으로, 내가 만든 자료형인 `MYST`에 `int` 파트와 `float` 파트가 있다는 의미이다.

즉, 구조체를 선언한 상태에서는 단순히 데이터 타입을 정의한 것이므로 메모리가 할당되지 않고 변수가 생성되지 않는다.

구조체 변수를 선언해서 사용해야 변수가 생성되고 메모리가 할당된다.

구조체 변수 선언하는 법

• `구조체변수이름 변수명;`

일반 변수를 선언하는 방식과 똑같다.

• 선언한 자료형들을 묶어서 만들었기 때문에 해당 자료형들의 크기를 합하면 구조체의 크기이다.

▷ 예시

typedef struct _tagMYST
{
	int a;
    float b;
} MYST;

int main()
{
	// 구조체 변수 선언
	MYST c;  // c의 크기 = 8byte (int형 4byte + float형 4byte)
    
    // 구조체 크기 확인
    int iSize = sizeof(MYST);  // 8

	return 0;
}

 

sizeof()
선언한 변수나 특정 자료형의 크기가 어느 정도인지 알려주는 함수

iSize는 8

각각의 파트에 세부적으로 접근하고 싶을 때

• `선언한변수.파트이름`

내가 만든 자료형으로 선언한 변수 + 온점(.) + 내가 만든 자료형에서 접근하고 싶은 파트 이름

typedef struct _tagMYST
{
	int a;
    float b;
} MYST;

int main()
{
	MYST c;
    
    c.a = 5;  // int 파트 접근
    c.b = 3.62f;  // float 파트 접근

	return 0;
}

c.을 하면 a와 b가 선택지로 나옴.

`c.`을 입력하면 `a`와 `b`로 접근할 수 있다는 것을 알 수 있다.

기본 자료형 int를 구조체로 정의 및 선언했을 때

typedef int INT;

int main()
{
	INT a;  // int
}

컴파일러는 `INT`를 int로 받아들인다.

즉, 기본 자료형을 `typedef`로 정의하면 컴파일러는 해당 기본 자료형으로 받아들인다.


2. C 문법

C 문법으로 변경하는 법

[프로젝트] - [`프로젝트명` 속성] - [구성 속성] - [C/C++] - [고급] - '컴파일 옵션'에서 'C 코드로 컴파일' 선택

 

▷ C++ 문법으로 작성한 구조체

typedef struct _tagMYST
{
	int a;
    float b;
} MYST;

typedef struct _tagBig
{
	MYST m;
    int d;
    char e;
} BIG;

typedef int INT;

int main()
{
	_tagMYST m;  // C 문법에서는 오류

	return 0;
}

구조체 이름인 `_tagMYST`을 이용해 변수를 선언하면 C 문법에서는 오류가 발생한다.

C 문법에서는 오류로 뜸.

구조체 초기화 하는 법

배열 초기화 방법과 비슷하다.

• `구조체변수명 변수 = { 값1, 값2, ... };`

typedef struct _tagMYST
{
	int a;
	float b;
} MYST;

int main()
{
	// 구조체 초기화
	MYST c = { 30, 5.62f };  // 구조체 초기값 => int 파트 a = 30, float 파트 b = 5.62f

	return 0;
}

Q. c.b의 경우 5.62가 아닌 5.61999989로 표시되는데, 그 이유는?

A. 실수는 그 숫자를 정확하게 표현하는 것이 아니라 부동 소수점으로 최대한 비슷한 값을 찾는다.

때문에 실제 메모리 값에서 약간의 오차가 있을 수 있다.

C 문법으로 구조체 만드는 법

C 문법에서는 `struct`로 구조체라는 것을 명시해줘야 한다.

태그명은 `struct` 뒤에 쓴다.

struct 태그명
{
    구조체 멤버;
};  // 세미콜론 꼭 쓰기!

C 문법으로 구조체 선언하면 불편한 점

• 사용자가 직접 정의한 자료형은 매번 앞에 `struct`를 붙여서 구조체를 정확히 명시해줘야 한다.

• 자료형을 지칭하는 데 있어서 길이가 길어진다.

struct NewStruct
{
	int i;
    double d;
};

int main()
{
	struct NewStruct ns;  // struct 안 쓰면 오류
}

 

C++에서는 `typedef struct`로 자료형을 만들면 선언할 때 굳이 `struct`를 앞에 붙이지 않아도 된다.

다시 C++문법으로 변경하자.

 

C 문법으로 작성한 구조체는 C++ 문법에서도 오류가 뜨지 않는다.

typedef struct _tagMYST
{
	int a;
    float b;
};

typedef struct _tagBig
{
	MYST m;
    int d;
    char e;
};

typedef struct NewStruct
{
	int i;
    double d;
};

typedef int INT;

int main()
{
	// C 문법이지만 오류가 발생하지 않는다.
	struct _tagMYST m;    
    struct NewStruct ns;

	return 0;
}

구조체 포인터

• `구조체변수명*`

구조체도 자료형이기 때문에 포인터로 만들 수 있다.

typedef struct _tagMYST
{
	int i;
    float f;
} MYST;

int main()
{
	MYST s = {};
    
    MYST* pST = &s;  // 포인터 변수 pST에 s의 주소 저장
    pST + 1;  // 실제로는 8이 더해진다.

	return 0;
}

`pST`는 `s`의 주소를 저장하고, 주소로 접근하면 int형 멤버 `i`와 `float`형 멤버 `f`가 존재한다.

총 8byte이기 때문에 `pST`에 1을 더하면 실제로는 8이 더해진다.

 

`(*pST).i`처럼 세부적인 파트로 접근할 수 있다.

구조체 포인터 타입에서 매번 지칭해야 되는 번거로움이 있어서 역참조 이후에 파트를 지칭하는 것을 `->`로 한 번에 표현할 수 있다.

typedef struct _tagMYST
{
	int i;
    float f;
} MYST;

int main()
{
	MYST m = {};
    
    MYST* pST = &s;
    *pST;  // s의 주소로 접근 (역참조)
    
    //(*pST).i = 50;
    pST->i = 50;
    
    //(*pST).f = 10.5f;
    pST->f = 10.5f;

	return 0;
}

구조체는 기본 자료형과 다르게 멤버를 여러 개 가질 수 있다.

포인터로 구조체 타입을 지칭할 경우 역참조한 이후에 멤버를 선택해줘야 한다.