C. 문자열
1. C스타일의 문자열 표현
a. 문자열과 배열
옛날에는 아래와 같이 문자열의 배열로 문자를 표현했음
하지만 0을 만나야 문자열의 끝으로 인식하기 때문에 아래와 같이 작성해야 올바르게 출력됨
b. const 위치에 따른 의미
c. 문자열과 데이터
2. 문자열 함수
a. 공간 할당과 문자열 크기
문자열 공간을 크게 할당해도 문자열의 길이는 실제 들어가있는 문자열 갯수만 유효함
b. 가장 많이 사용하는 함수 3개
- 문자열 길이 : strlen
- 문자 복사 : strcpy
- 문자 연결 : strcat
😀 예제
#include <iostream>
using namespace std;
int main()
{
const int BUF_SIZE = 100;
char a[BUF_SIZE] = "Hello";
char b[BUF_SIZE] = "World";
char c[BUF_SIZE];
#pragma warning(disable:4996) //: 오류 잠시 꺼두기
int len = strlen(a);
cout << len << endl;
strcpy(c, a);
cout << c << endl;
cout << strcat(a, b) << endl;
}
✨ 실행결과
5
Hello
HelloWorld
c. 함수 직접 작성해보기
1) strlen 함수
✒ 인덱스를 활용해 문자열의 끝을 판단해 인덱스를 출력
// [Hello.........]
int StrLen(const char* str) {
int i = 0;
//문자열의 끝이 0인걸 응용
while (str[i]) {
i++;
}
return i;
}
2) strcpy 함수
✒ 인덱스와 포인터를 활용한 복사
// [..............]
// [Hello.........]
char* StrCpy(char* dest, char* src) {
char* rest = dest;
//1. 인덱스로 해결하는 방법
int i = 0;
while(src[i]) {
dest[i] = src[i];
i++;
}
dest[i] = 0;
//2.포인터를 직접 이용하는 방법
while (*src) {
*dest = *src;
dest++; //주소값 1 증가
src++;
}
*dest = 0;
return dest;
}
3) strcat 함수
✒ 인덱스와 포인터를 활용한 복사
char* StrCat(char* dest, char* src) {
char* ret = dest;
int len = StrLen(dest);
//1. 인덱스 방식
int i = 0;
while (src[i]) {
dest[len + i] = src[i];
i++;
}
//dest[len + i] = 0;
//2. 포인터 방식
while (*dest) {
dest++; //dest의 마지막까지 주소 이동
}
while (*src) { //src의 마지막 값까지 복사
*dest = *src;
dest++;
src++;
}
return ret;
}
d. 전체 코드
#include <iostream>
using namespace std;
// [Hello.........]
int StrLen(const char* str) {
int i = 0;
//문자열의 끝이 0인걸 응용
while (str[i]) {
i++;
}
return i;
}
// [..............]
// [Hello.........]
char* StrCpy(char* dest, char* src) {
char* rest = dest;
//1. 인덱스로 해결하는 방법
int i = 0;
while(src[i]) {
dest[i] = src[i];
i++;
}
dest[i] = 0;
//2.포인터를 직접 이용하는 방법
while (*src) {
*dest = *src;
dest++; //주소값 1 증가
src++;
}
*dest = 0;
return dest;
}
char* StrCat(char* dest, char* src) {
char* ret = dest;
int len = StrLen(dest);
//1. 인덱스 방식
int i = 0;
while (src[i]) {
dest[len + i] = src[i];
i++;
}
//dest[len + i] = 0;
//2. 포인터 방식
while (*dest) {
dest++; //dest의 마지막까지 주소 이동
}
while (*src) { //src의 마지막 값까지 복사
*dest = *src;
dest++;
src++;
}
return ret;
}
int main()
{
const int BUF_SIZE = 100;
// [Hello.........]
char a[BUF_SIZE] = "Hello";
char b[BUF_SIZE] = "World";
char c[BUF_SIZE];
#pragma warning(disable:4996) //: 오류 잠시 꺼두기
int len = StrLen(a);
cout << len << endl;
StrCpy(c, a);
cout << c << endl;
cout << StrCat(a, b) << endl;
}
D. 참조
1. 참조와 포인터 전달방식
a. 값(복사) 전달 방식
- 본체에 영향을 줄 수 없고 정말 값만 전달
- 복사하는 (StatInfo)값이 커지면 부담이 커짐
참조와 포인터의 관계를 알기 위해 값 전달 방식을 먼저 구현해봄
❔ 예제 : 값(복사) 전달 방식
#include <iostream>
using namespace std;
struct StatInfo {
int hp;
int attack;
int defence;
};
//값(복사) 전달 방식
void PrintByCopy(StatInfo player) {
cout << "--------------------" << endl;
cout << "HP : " << player.hp << endl;
cout << "ATT : " << player.attack << endl;
cout << "DEF : " << player.defence << endl;
cout << "--------------------" << endl;
}
int main()
{
StatInfo player = { 100, 10, 1 };
PrintByCopy(player);
}
✨ 실행결과
--------------------
HP : 100
ATT : 10
DEF : 1
--------------------
b. 주소 전달 방식(pointer)
- 원격으로 원본 데이터에 영향을 줄 수 있는 방식
- 복사하는 (StatInfo)값이 커져도 포인터라 부담이 없음
❔ 예제 : 주소 전달 방식
//2) 주소 전달 방식
void PrintByPointer(StatInfo* player) {
cout << "--------------------" << endl;
cout << "HP : " << player->hp << endl;
cout << "ATT : " << player->attack << endl;
cout << "DEF : " << player->defence << endl;
cout << "--------------------" << endl;
}
...
int main(){
...
PrintByPointer(&player);
}
c. 참조 전달 방식
& 참조 연산자를 사용해서 포인터처럼 사용하지만 코드는 값 복사방식(a)을 사용
실제로 포인터와 실행되는 내부 구조는 똑같음
- 원격으로 원본 데이터에 영향을 줄 수 있는 방식
- 복사하는 (StatInfo)값이 커져도 주소를 넘겨 부담이 없음
❔ 예제 : 참조 전달 방식
//3) 참조 전달 방식
void PrintByRef(StatInfo& player) {
cout << "--------------------" << endl;
cout << "HP : " << player.hp << endl;
cout << "ATT : " << player.attack << endl;
cout << "DEF : " << player.defence << endl;
cout << "--------------------" << endl;
}
...
int main(){
...
StatInfo& ref = player; //ref가 별칭이 됨
PrintByRef(ref);
PrintByRef(player); //이렇게 바로 넣어줄 수도 있음
}
두 방식 중 어느 방식이 더 많이 사용되느냐의 차이는 그냥 선호도일뿐!
💥 Warning
포인터를 사용하는 경우, nullptr로 없음을 표현할 수 있어서
그에따른 처리를 해줘야 함 (버그 발생 빈도의 95%)
👉 그에 반해 참조는 비어있는 개념이 없다
2. 참조 사용시 알아둬야 할 내용
a. const 참조 (변경 X)
원본을 변경하려고 사용하는게 아님을 명시할 때 사용 (그냥 복사 비용을 아끼려고 사용한 경우)
b. OUT (변경 O)
실제로 전처리 단계에서 의미없이 삭제되지만, 수정하는 목적으로 사용됨을 명시해줌
(값을 바꾸고, null 체크하는게 귀찮아서 받은 경우)
'프로그래밍 언어 > C++' 카테고리의 다른 글
[자료형(data type)] C++ 파생형 포인터 총정리 (0) | 2023.09.09 |
---|---|
[자료형(data type)] C++ 파생형 배열 총정리 (0) | 2023.09.08 |
[게임 프로그래머 입문 올인원] 포인터와 배열 : 포인터 (20, 21강) (0) | 2023.09.06 |
[게임 프로그래머 입문 올인원] 포인터와 배열 : 배열 기초 (18강) (0) | 2023.09.06 |
[자료형(data type)] C++ 파생형 함수 총정리 2 (0) | 2023.09.06 |