오늘의 TIL 목차 (22.08. 10)
- 문자열 함수 ( strcpy_s, strlen, strcat_s, strcmp )
- 구조체, 구조체 배열 ( struct )
- 공용체 ( union )
문자열 함수
1. 문자열 복사 2. 문자열 길이 3. 문자열 결합 4. 문자열 비교
[ strcpy_s() ]
: 문자열 복사 함수
int strcpy_s(char* 복사본, unsigned int 복사본 메모리 공간의 크기, char const* 복사할 문자열 / 주소);
char szName[32] = "milk";
char szTemp[32] = "dainn";
strcpy_s(szName, sizeof(szName), szTemp);
// 메모리 공간은 들어갈 문자열의 크기보다 크고 복사본이 저장될 메모리 공간의 크기보다 작아야 한다.
// dainn\0인 6보다 크고 szName의 메모리 공간 32보다 작아야함
cout << szName << endl; // dainn 출력
//strcpy_s("rainnyday", sizeof("rainnyday"), "dainn")
//문자열 변수를 선언하지 않고 문자열 자체를 복사본으로 바꾸는 건 불가능
[ strlen() ]
: 문자열 길이를 구하는 함수, null문자를 제외한 순수한 문자 길이만 구해주는 함수
strlen( 문자열 주소 or 문자열 상수 ); // 문자열 상수는 "dainn"
char szName[10] = "dainn";
strlen("milk"); // 4
strlen(szName); // 5
※ sizeof(szName)은 배열의 크기 10, strlen(szName)은 배열 안의 문자열의 길이(널 제외) 5
[ strcat_s() ]
: 문자열 결합 함수, 두 문자열을 결합하여 하나의 문자열의 형태로 만들어주는 함수
strcat_s(저장될 문자열 주소, 결합 문자열 저장될 문자열의 메모리 공간, 결합시킬 문자열 상수 / 주소)
char szName[32] = "milk";
char szTemp[32] = "Dainn";
strcat_s(szTemp, 24, "_GoHome"); // Dainn_GoHome
strcat_s(szName, 30, szTemp); // milkDainn_GoHome
// 메모리 공간 크기는 두 문자를 결합했을 때의 크기 이상이면 됨 (널 포함)
// 메모리 공간 선언 시 결합된 문자가 저장될 메모리 공간의 크기보다 크면 안됨
[ strcmp() ]
: 문자열의 일치 여부를 판단하는 함수, 비교하는 두 문자열이 일치할 경우 0을 리턴
strcmp(문자열, 문자열); // 문자열은 문자열 주소 또는 문자열 상수 ("") , 변수명은 안됨
!strcmp(문자열, 문자열); // 일치하면 0을 반환하기 때문에 !(NOT 연산자)를 사용하여 1을 반환
char szCompare[32] = "dainn";
if (!strcmp("dainn", "dainn\0"))
cout << !strcmp("dainn", "dainn\0") << endl;
if (strcmp(szCompare, "dainn\0"))
cout << strcmp(szCompare, "dainn\0") << endl;
출력 결과:
1 // !를 붙여 일치했을 때 1을 반환하도록 함 (이 방식을 사용)
0 // !을 안 붙이면 일치했을 때 0 반환
구조체
1. 구조체 2. 구조체 배열
[ 구조체 (struct) ]
: 사용자 정의 자료형 ( 여러 타입의 자료형, 함수, 구조체를 담아 정의 )
[자료형 정의]
struct 구조체명
{
매개변수
}; // 구조체 세미콜론 명심
[접근 방법]
구조체 변수명.매개변수명
구조체 주소(포인터)->매개변수명
// typedef를 이용하여 tagInfo를 DAINN으로 대신 사용할 수 있게 자료형명 정의
typedef struct tagInfo
{
int iX;
int iY;
}DAINN;
tagInfo tDainn = {}; // 구조체 자료형의 매개변수 0 또는 널로 초기화
tDainn.iX = 30; // 매개변수 지정 연산자(.)을 통해 tagInfo 자료형 안의 매개변수 iX에 접근
&tDainn->iX = 30; // 포인터 등의 주소는 *를 통해 값으로 변경 또는 화살표 연산자 사용
※ 구조체의 매개변수 접근 방법
- 이름은 온점(.)을 통해서, 주소는 화살표 연산자(→)를 통해서 매개변수에 접근한다.
- 변수명.매개변수
- 주소→매개변수
- (*주소).매개변수
- (*(&변수명)).매개변수
■ 기능 / 주의
- 구조체의 크기는 멤버 변수 중 가장 큰 자료형의 크기 만큼의 메모리 블럭으로 생성된다.
- 가장 큰 메모리 크기만큼 블럭이 생성되며, 매개 변수 선언 순서에 따라 차례로 들어간다 (연속)
- 멤버 변수 선언 순서에 따라 메모리 블럭이 낭비될 수도 있다.
( 공간 낭비를 최소화하기 위해 자료형의 크기가 작은 순으로 선언해야 한다. ) - 배열의 경우 같은 자료형을 여러번 선언하는 문법이지 자료형이 아니기 때문에 기존 자료형의 크기 기준으로 메모리 할당이 된다. ( char szName[30] = {}; 의 경우 기존 자료형의 크기 1로 할당된다. 메모리 공간 1*30 소모 )
- 구조체 안에서 메모리 블럭의 크기는 기본 자료형을 기준으로 생성되고, 사용자 정의 자료형(구조체 안의 구조체)은 독립적인 크기로 자리잡는다.
struct tagInfo
{
char cA; //1
int iA; // 4
float fA; //4
double dA; //8
int Sum(int a, int b) {
return a + b;
}
};
void main(void)
{
tagInfo tInfo = {}; // 구조체 안의 멤버변수 전부 0 / 널로 초기화
cout << tInfo.iA << endl;
//cout << tInfo.cA << endl;
cout << " =======" << endl;
cout << &tInfo.fA << endl; // tInfo의 매개변수 fA의 주소 출력
cout << &tInfo << endl; // 구조체 tInfo의 주소는 첫번째 매개변수 (시작 주소)
cout << &(tInfo.iA) << endl; // tInfo의 주소와 동일 (iA가 첫번재 매개변수)
// 첫번째 매개변수가 char일 경우, 주소 출력 안됨 왜지 ?
cout << sizeof(tInfo.dA) << endl;
cout << sizeof(tInfo) << endl; // 함수 크기는 제외되고 출력
/*cout << " =====" << endl;
cout << &tInfo << endl;
cout << &tInfo.cA << endl;
cout << &tInfo.iA << endl;
cout << &tInfo.fA << endl;
cout << &tInfo.dA << endl;
}
■ 예시
#include <iostream>
using namespace std;
typedef struct tagInfo
{
char szName[32]; // 메모리 크기 1, 32개
int iKor; //4
float fAver; //4
void Render() // 메모리 공간 사용 안하는 듯
{
cout << "안녕" << endl;
}
int Sum(int _iA, int _iB) // 선언부 따로 안해줘도 됨
{
return _iA + _iB;
}
}INFO; //typedef로 tagInfo 대신 INFO도 사용 가능
void main(void)
{
INFO tStruct = {{'a'},{50},{5.f}}; // 선언 및 초기화 (매개변수별로 중괄호로 묶어줘야함)
tagInfo tInfo = { 'a' ,98 }; // 중괄호로 묶지 않으면 98은 iKor이 아닌 배열 szName에 들어감
INFO* p = &tInfo; // 포인터 p에 tInfo 변수의 시작 주소 저장 (tagInfo와 INFO는 같은 자료형)
cout << tStruct.iKor << endl; // 50 출력
cout << p->szName << endl; // 주소로 매개변수 접근, szName[0]번째 접근 // a 출력
cout << p->szName[1] << endl; // p(&tInfo)의 szName[1]은 98 (b) // b 출력
int iSum = tStruct.Sum(10, 20);
cout << iSum << endl; // 30 출력
tStruct.Render(); // "안녕" 출력
}
※ 구조체에 배열이 있을 경우, {} 안에 초기화 시 매개변수별로 중괄호를 묶지 않으면 순서대로 매개변수에 들어가는 것이 아니라 배열 안에 들어감 ( 배열이 없을 경우 중괄호로 묶지 않아도 매개변수 순서대로 초기화됨 )
- INFO tStruct = { 'a', 65 } 는 szName[0] == a, szName[1] == A
- INFO tStruct = { { 'a', 'b'}, {65} } 는 szName에 순서대로 a, b iKor == 65 가 됨
[ 구조체 배열 ]
: 2차원 배열처럼 구조체 한묶음을 여러 개 사용
struct tag
{
char szName[10]; // = " ", = {}; 로 초기화 시 오류
char cA;
int iA;
};
void main(void)
{
tag tName[2] = { {"다인", 98, 3}, {{'A','B'}, 97, 'A'} }; // tag 자료형의 tName 변수 2개 생성
cout << tName[0].cA << endl; // 98 (b)
cout << tName[1].iA << endl; // A (65)
// 구조체 안의 문자열 배열은 문자열 함수를 사용하여 대입
strcpy(tName[0].szName,sizeof(tName[0].szName),"배고파");
cout << tName[0].szName << endl; // 문자열 상수는 szName[인덱스] 지정 불가
cout << tName[1].szName[1] << endl; // 문자열 배열(원소)는 szName[인덱스] 지정 가능
}
출력결과:
b
65
배고파
B
※ 구조체 안의 문자열 매개변수
- 구조체 안에서 문자열 초기화 ( = " " , = {}; ) 불가능
- szName[10] = "dainn"; 이런 식으로 대입할 수 없고 문자열 함수를 이용하여 대입 가능
- 변수 선언 후 문자열 초기화 시 상수( " ")로 대입하면 .szName[인덱스] 지정 불가능
- { 'A', 'B' } 등 배열로 대입했으면 szName[인덱스]에 따라 해당 인덱스의 원소 호출
- tName[1] 초기화 구문에서 { 'A', 'B' }를 따로 묶어주지 않았다면 뒤의 97, 'A' 도 다음 매개변수인 cA와 iA에 차례로 대입되지 않고 szName[10] 배열의 크기만큼 배열 안에 순서대로 대입 후 다음 매개변수에 대입한다. szName[10]은 인덱스 0 순서대로 A B a A 가 되고 cA와 iA는 0 자동 초기화 되는 것.
■ 예시 ( + 포인터 사용 )
struct tagInfo
{
char szName[32]; // 자료형 크기 1 , 32개 // 멤버 변수
int iKor; //4
float fAver; //4
};
typedef struct tagDainn
{
//char szArray[10] = {};
int iA;
long long lA;
float fA;
int Sum(int _iA, int _iB) {
return _iA + _iB;
}
}Dainn, tag; // typedef로 tagDainn 자료형을 다른 이름(Dainn, tag)으로도 사용 가능
void main(void)
{
tagInfo tStudent[2] = {}; // tagInfo 자료형의 tStudent 배열 2개 선언 및 초기화
cout << sizeof(tagInfo) << endl; // tagInfo 자료형의 크기는 32 + 4 + 4인 40 // 40
cout << sizeof(tStudent) << endl; // tagInfo 자료형 구조체 배열 (2개) 이므로 40 * 2 = 80 // 80
cout << sizeof(tStudent) / sizeof(tagInfo) << endl; // 배열 크기 / 자료형 크기 = 배열 개수 // 2
for (int i = 0; sizeof(tStudent) / sizeof(tagInfo2) > i; ++i)
{
tStudent[i].fAver = (float)i;
tStudent[i].szName[0] = 97 + i; // szName은 문자열이므로 a와 b가 들어감
cout << tStudent[i].fAver << "\t" << tStudent[i].szName[0] << endl; // 0 a / 1 b
}
cout << tStudent[1].szName << endl;
// 구조체 배열.매개변수배열에서 매개변수 배열에 대괄호 연산자를 안쓰면 0번째 배열 출력
// b 출력
[포인터]
tagInfo tDainn[3] = {}; // 구조체 배열의 경우 배열과 마찬가지로 배열 이름은 주소
tagInfo* pDainn = nullptr; // tagInfo 자료형의 포인터 생성
pDainn = tDainn; // tDainn은 배열 이름이므로 주소
tagDainn td = {}; // 아래 tagDainn과 Dainn은 같은 자료형 (typedef 해준 것)
Dainn* p = &td; // 포인터에 구조체 변수의 주소를 넣어야 함
tDainn[1].fAver = 4.5f; // 1번째 tDainn의 매개변수 fAver에 대입
tDainn->fAver = 200; // 주소로 접근 시 화살표 연산자 사용 (주소는 0번째 주소 (시작주소)를 가짐)
(*p).Sum(10,20); // (*주소).매개변수 로 접근 가능
cout << pDainn->fAver << endl; // pDainn과 tDainn 주소 동일 (0번째 구조체) // 200 출력
pDainn = &tDainn[1]; // 1번째 구조체의 주소를 포인터에 대입
cout << pDainn->fAver << endl; // pDainn은 1번째 구조체 주소 // 4.5 출력
}
공용체
[ 공용체 (union) ]
: 데이터의 집합으로 멤버 중 가장 큰 메모리 공간의 크기만큼을 할당하고 모든 멤버 변수가 그 공간을 공유하여 사용하는 자료형
union uniInfo
{
//short sA;
int iB;
float fC;
};
struct tagInfo
{
short sA;
int iB;
};
void main(void)
{
//cout << sizeof(tagInfo) << endl;
//cout << sizeof(uniInfo) << endl;
//tagInfo tInfo = { 10, 20 };
//uniInfo uInfo = { 10 };
//cout << &(uInfo.sA) << endl;
//cout << &(uInfo.iB) << endl;
/*uniInfo uInfo;
uInfo.iB = 10;
uInfo.fC = 3.14f;
cout << uInfo.iB << endl;
cout << uInfo.fC << endl;*/
}
union uniInfo
{
char cA; // 1
short sB; // 2
};
void main(void)
{
uniInfo uInfo = { 'c' };
cout << sizeof(uInfo) << endl; // 가장 큰 메모리 공간 short만큼 할당해서 공용 사용
cout << uInfo.cA << endl; // 2
uInfo.sB = 100;
cout << uInfo.sB << endl; // 100
cout << &(uInfo.cA) << endl; // 엥 이상함 주소가 출려 ㄱ안됨
cout << &(uInfo.sB) << endl; // 주소
}'C++' 카테고리의 다른 글
| [TIL 14장] 메모리 함수, 콘솔/파일 입출력 함수[text] (0) | 2022.08.12 |
|---|---|
| [TIL 13강] 열거체, C언어 동적할당(feat. Heap) (0) | 2022.08.12 |
| [TIL 11장] 문자열, 함수 포인터 (0) | 2022.08.08 |
| [TIL 10장] 2차원 배열 (0) | 2022.08.05 |
| [TIL 9장] 이중 포인터 개념, 배열, 디버깅 (0) | 2022.08.04 |