구조체와 포인터

-> 구조체와 같이 연속된 메모리에 멤버 변수들이 나열된다.

-> 단, 연속된 메모리를 사용한다고해서 구조체의 이름또한 포인터라고 착각하면 안된다.

 

 

구조체 포인터 선언

typedef struct tagInfo
{
	char	chName[16];
	int		iKor;
	int		iEng;
	int		iMath;
	int		iTotal;
	float	fAver;
}INFO;

여기서 포인터 선언을 할 때 pInfo.chName에 접근이 불가능한 이유는

.(dot)연산자는 구조체에 의한 연산자이지 포인터에 의한 연산자가 아니기 때문이다.

 

멤버 접근 포인터 연산자(->)

->는 역참조 연산자와 .(dot) 연산자를 합친 것과 같다.

 

구조체의 크기

-> 구조체의 크기는 멤버 젼수들의 크기를 합한 것이 아니다.

#1. 멤버 변수들을 모두 펼친다.

typedef struct tagSize
{
	char	chSize;		// 1
	int	iSize;	        // 4
	float	fSize;		// 4
	double	dSize;		// 8
}SIZE;

#2. 크기가 가장 큰 멤버 변수를 찾는다. -> 기준

double	dSize;		// 8

#3. 기준 만큼 메모리를 할당하고, 순차적으로 채워 넣는다.

chSize + iSize = 5

-> 8byte의 메모리를 할당한 상태

 

#4. 채워 넣을 수 없을 경우 추가 할당을 한 후 다시 채워 넣는다.

chSize + iSize + fSize = 9가 나오기 때문에 추가 할당

-> 16byte의 메모리를 할당한 상태

 

fSize + dSize = 12byte가 나오기 때문에 추가 할당

-> 24byte의 메모리를 할당한 상태

 

#5. 모두 채워 넣은 후 합산한 결과가 최종 크기가 된다.

8byte 기준 : chSize(1byte) + iSize(4byte)  = 5byte

8byte 기준 : fSize  = 4byte

8byte 기준 : dSize = 8byte

 

최종크기 = 24byte 

 

이 때, 빈 공간이 생기게 되는데 이를 padding byte 라고 한다.

 

padding byte를 최소화 하는 것이 메모리 절약에 좋기 때문에

멤버로 문자 배열을 선언할 경우 2의 N승으로 만드는 습관을 들이는 것이 좋다.

 

구조체 멤버로 구조체를 가질 경우의 크기

-> 두 구조체를 모두 펼친 후 크기가 가장 큰 멤버 변수가 기준이 된다.

typedef struct tagSize
{
	char	chSize;		// 1
	int	iSize;		// 4
	float	fSize;		// 4
	double	dSize;		// 8
}SIZE;

typedef struct tagSize1
{
	int  	   iSize;  // 4
	float	   fSize;  // 4
	long longll Size;  // 8
	tagSize    tSize;  // 24
}SIZE1;

-> 기준을 토대로 각 구조체의 크기를 따로 계산한다.

-> 이후, 합산한 결과가 최종 크기가 된다.

최종 크기 = 40byte 

 

자기 자신을 멤버로 가지는 구조체

-> 자기 자신을 멤버로 가질 경우에는 재정의 된 이름이 아닌 본연의 이름을 가져야만 한다.

-> 컴파일 단계에서 구조체의 크기를 계산하기 위해 멤버 구조체를 펼지게 된다.

-> 하지만 펼쳐도 구조체가 또 존재하기 때문에 계속해서 무한루프를 돌게된다.

(무한루프 + 사이즈를 계산할 수 없음.)

-> 이 경우를 예방하기 위해서 포인터 형으로 선언을 해야한다.

-> 포인터는 어떤 자료형이든 고정된 크기(4byte)를 가지기 때문이다.

 

 

 

 

+ Recent posts