구조체와 포인터

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

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

 

 

구조체 포인터 선언

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)를 가지기 때문이다.

 

 

 

 

구조체

-> 사용자 정의 자료형이다.

-> int, float, double 같은 자료형들은 기본 자료형이다.

-> 사용자 정의 자료형이라고 해서 몇 byte 크기만큼 어떤식으로 읽을 수 있게 만들 수 없다.

-> 기존에 있던 자료형들을 모아서 데이터 덩어리 형태로 만든다.

-> 데이터 집합이라고 생각하면된다.

 

구조체의 형태

struct 자료형이름
	{	// 여기부터

		기본 자료형 + 변수명
		기본 자료형 + 변수명
		기본 자료형 + 변수명

	}

구조체 변수 선언

struct 자료형	변수명;
struct tagInfo	tInfo;

 

구조체의 멤버 접근

-> 구조체의 멤버에 접근하는 방법은 연산자를 사용한다.

.(dot) 연산자

struct tagInfo			tInfo = { "AAA", 10, 20, 30 };
cout << tInfo.szName << endl;
cout << tInfo.iKor << endl;
cout << tInfo.iEng << endl;
cout << tInfo.iMath << endl;
cout << tInfo.iTotal << endl;
cout << tInfo.fAver << endl;

 

구조체의 멤버 변수 대입

구조체의 멤버 변수의 값을 변경하려고 하는데 정수 값은 바뀌지만 문자는 바뀌지 않는다. 왜 그럴까?

이유는 문자 배열이기 때문에 즉, 주소를 다루기 때문이다.

 

문자 배열은 상수이기 때문에 일반 형식으로 대입이 불가능하다.

 

하지만 strcpy_s를 사용으로 변경은 가능하다.

 

typedef

-> type(타입) define(정의하다)

-> 자료형을 다른 이름으로 재 정의 한다.

-> 자료형에 별명을 붙여서 사용한다는 의미.

 

장점

-> 긴 자료형을 줄여서 사용할 수 있다.

-> 유지보수가 좋다.

예를 들어 short 자료형을 int 자료형으로 바꾸는 작업을 할 때 다음과 같이 편리하게 할 수 있다.

typedef		자료형	별명
typedef		short 	_short;

_short	iB = 20;
typedef		자료형  별명
typedef		int 	   _int;

_int	iB = 20;

 

C구조체와 C++구조체의 차이점
-> struct 키워드 내부에 typedef이 정의되어 있는지 여부
-> C에서는 struct tagInfo 라고 자료형을 지어야 한다.
-> C++에서는 tagInfo로 자료형을 지을 수 있다.

 

struct나 class에서 초기화 값 변경을 바꾸려고 const 멤버 변수를 쓰지 않는다.

참조(&) 멤버변수의 경우도 마찬가지

'Programming > C++ Basic' 카테고리의 다른 글

C++ 동적 할당(C, C++기반), malloc, calloc  (0) 2020.09.01
C++ 구조체와 포인터  (0) 2020.08.31
C++ 문자열 함수  (0) 2020.08.31
C++ 문자 배열과 문자열 상수  (0) 2020.08.28
C++ 2차원 배열  (0) 2020.08.28

#1. strcpy_s

-> 문자열 복사 함수

( c에서는 strcpy로 사용을 하였지만 c++로 넘어오면서 strcpy_s로 바뀌었다.)

 

strcpy_s(목적지, 크기, 출발지)

 

목적지

-> 어디에 복사를 할 것인지 복사 받을 메모리의 시작 주소를 전달

 

크기

-> 얼마만큼 복사를 수행할 것인지 크기를 전달(byte 단위)

 

출발지

-> 어디에 있는 데이터를 복사할지 시작 주소를 전달

#2. strcat_s

-> 문자열 결합

-> 기존 문자열 뒤에 문자를 이어 붙인다.

 

strcat_s(목적지, 크기, 출발지)

 

목적지

-> 이어붙일 메모리의 시작 주소

 

크기

-> 얼마만큼 수행할 것인지 크기를 전달(byte 단위)

 

출발지

-> 어디에 있는 데이터를 이어붙일지 시작 주소를 전달

	char szDst[20] = "Hello";
	char szSrc[20] = "World";

	cout << szDst << endl;
	cout << szSrc << endl;
	cout << "-------------------------" << endl;
	strcat_s(szDst, 20, szSrc);
	cout << szDst << endl;
	cout << szSrc << endl;

 

#3. strlen

-> 문자열의 길이를 반환하는 함수.

-> 단, NULL문자를 제외한 순수 문자열의 길이만 반환

	char	szBuff[20] = "Hello";
	
	cout << "sizeof: " << sizeof(szBuff) << endl;
	cout << "strlen: " << strlen(szBuff) << endl;

-> NULL문자를 포함하여 문자열의 길이를 반환하는 방법

void Func(char* m_pBuff)
{
   strlen(m_pBuff) + 1;
}

-> strlen을 사용하지 않고 문자열의 길이를 알아내는 방법은 다음과 같다.

int _len = 0;
while (_szBuff[_len] != '\0')
		_len++;

위와 같이 선언을 하게되면 해당 문자열에서 NULL문자가 나올때까지 비교를 하면서 문자열의 길이를 파악할 수 있다.

 

 

#4. strcmp

-> 두 문자열이 같은지를 비교하는 함수.

-> 두 문자가 같으면 0, 다르면(대소문자도 포함) 0이 아닌 값

(두 문자의 아스키코드 값이 같아도 동일하게 0이 나온다.)

char	szDst[20] = "Hello";
char	szSrc[10] = "Hello";

if (!strcmp(szDst, szSrc)) // strcmp(szDst, szSrc)의 값이 1이 아닐 경우
	cout << "같다" << endl;
else
	cout << "다르다" << endl;
    
cout << !strcmp(szDst, szSrc) << endl;

char	szDst[20] = "Hello";
char	szSrc[10] = "HellO";

if (!strcmp(szDst, szSrc)) // strcmp(szDst, szSrc)의 값이 1이 아닐 경우
	cout << "같다" << endl;
else
	cout << "다르다" << endl;
    
cout << !strcmp(szDst, szSrc) << endl;

'Programming > C++ Basic' 카테고리의 다른 글

C++ 구조체와 포인터  (0) 2020.08.31
C++ 구조체(Struct)  (0) 2020.08.31
C++ 문자 배열과 문자열 상수  (0) 2020.08.28
C++ 2차원 배열  (0) 2020.08.28
C++ 배열과 포인터  (0) 2020.08.28

문자 배열의 선언

char ch[10];

문자 배열의 초기화

-> 배열의 초기화는 {}를 사용했다.

-> 하지만 문자 배열의 초기화는 ""를 사용한다.

 

문자 배열은 배열 한칸 당 문자 하나씩 삽입이 된다.

마지막 문자가 삽입 된 후 다음 칸에는 자동으로 NULL문자가 삽입 된다.

 

NULL문자가 삽입되는 이유

-> NULL문자는 컴퓨터에게 해당 문자의 마지막 부분까지 읽으라고 명령을 하는 것이다.

 

예를 들어보자.

처음에 Hello라는 문자 배열을 선언하면 H, e, l, l, o 5개의 문자가 만들어진다.

여기서 H 부터 o까지 읽고 그 다음엔 NULL문자가 삽입이 된다.

 

NULL문자는 찾을 수 없을 경우 다음과 같이 알 수 없는 문구로 표시가 되는데,

원래는 빈 공간으로 표시가 된다.

배열의 이름은 주소이다.

-> cout 으로 배열의 이름을 전달하면 주소가 나온다.

-> 문자 배열은 같은 배열인데 주소가 나오는 것이 아니라 문자가 출력이 된다.

-> cout은 객체이다.

-> 단, 해당 주소가 char*일 경우에는 주소로 출력하는 것이 아닌 해당 주소에 있는 문자를 출력해준다.

 

문자 배열의 원소 접근

-> 배열처럼 인덱스 접근을 통한 읽기/쓰기가 가능하다.

char	ch[30] = "Hello";

	ch[2] = 'L';
	cout << "\t" << ch[2] << endl;
	cout << "\t" << ch << endl;

NULL문자의 중요성

-> 문자 배열의 크기를 설정할 때 NULL문자를 고려해서 크기를 설정해야된다.

 

예를 들어보자.

 

1byte 5개를 준비하고 6개의 문자를 넣으려고 시도한다.

이 경우 마지막에 들어갈 NULL문자는 할당한 메모리 공간이 아니다!!
-> 사용자가 할당하지 않은 메모리 공간의 접근 시도로 인해서 오류가 발생한다.


하지만 1byte 6개를 준비하고 Hello를 선언하면?

문제없이 잘 작동한다.

6byte로 만들어진 문자 배열 같은 경우는

첫 번째 문자부터 0, 1, 2, 3, 4, NULL 순서대로 읽으면 된다.

문자열 상수

-> 문자열 상수는 Data 영역에 할당이 된다.

(Data 영역에 배열의 형태로 공간을 만든다.)

-> 이후 문자 하나씩 대입하고, 마지막에는 NULL문자를 대입한다.

-> 메모리 할당이 완료되면 할당된 공간의 시작 주소를 반환한다.

cout << "Hello" << endl;

위에 Hello를 출력한 것은 Data 영역의 주소를 출력하는 것과 같은 말이다.

 

 

문자열 상수를 다루는 방법

-> 문자열 상수는 Data 영역의 주소를 반환하니, 주소를 저장할 변수를 만들어 사용한다.

char*	ch = "Hello";

 

원소 접근

-> Data 영역에 등록된 문자는 상수의 성질을 가진다.

	char*	ch = "Hello";
	ch[2] = 'L';		// 오류 발생
	cout << ch[2] << endl;

문자 배열과 문자열 상수의 차이점

#1 문자 배열

-> const가 *(에스크리터) 뒤에 붙는 경우와 동일하다.

-> 역참조를 통한 값 변경은 가능

-> 배열의 이름은 상수포인터이기 때문에 주소 값 변경은 불가능

 

#2 문자열 상수

-> const가 *(에스크리터) 앞에 붙는 경우와 동일하다.

-> 역참조를 통한 값 변경은 불가능

-> 주소 값 변경은 가능

 

문자 배열의 초기화

-> 컴퓨터가 문자 배열의 선언과 동시에 초기화 시 문자를 하나하나 대입해준다.

char	ch[10] = "Hello";

초기화 후 대입

-> ch는 주소를 가지는 포인터 변수

-> "Hello" 는 Data 영역의 주소

 

 

 

'Programming > C++ Basic' 카테고리의 다른 글

C++ 구조체(Struct)  (0) 2020.08.31
C++ 문자열 함수  (0) 2020.08.31
C++ 2차원 배열  (0) 2020.08.28
C++ 배열과 포인터  (0) 2020.08.28
C++ const와 포인터  (0) 2020.08.28

+ Recent posts