C언어 공부

C++ 심화 - 3 문자열과 네임스페이스 그리고 레퍼런스 타입

당혜성 2025. 3. 20. 01:44

기존에 문자열을 복사하려면 상당히 복잡하게 하였다.

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>

int main() {
	char name[100];
	strcpy(name, "hi");

	printf("%s", name);
	return 0;
}

기존에 strcpy를 사용해 이런 형식으로 사용했을것이다.

 

C++는 기존 문자열 사용의 불편한점을 해결한 클래스가 존재한다.

 

바로 std::string이다

std::string

C++에서 문자열을 활용하기 위한 클래스형 문자열 타입

 

string헤더파일에 정의되어 있다.

std::string에는 문자열을 이용한 여러가지 동작을 할 수 있도록 여러 멤버함수가 정의되어 있다.

 

또한 문자열의 포인터를 자동으로 관리해주기 때문에 하나하나 포인터를 관리할 필요 없이 정적인 형태의 클래스 인스턴스로 활용할 수 있다.

 

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <string>

int main() {
	std::string name = "hi";
	
	return 0;
}

std:: 형태로 사용한다.

#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>
#include <string>

int main() {
	std::string name = "hi";
	printf("%s", name.c_str());
	
	return 0;
}

출력은 이런 형태로 하면 된다.

 

기존 printf("%s", name); 형태로 실행을 해보면 이상한 값이뜬다.

 

이것은 std::string name이 포인터로 할당되서 그렇다.

 

C++를 사용하면 이렇게도 가능하다.

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>

int main() {
	std::string name = "hi";
	
	std::cout << name;

	return 0;
}

#include <iostream>을 하고 std::cout << 변수 이름을 하면 된다.

 

하지만 printf로만 출력 하겠다.

 

std::cout은 따로 입문으로 적어서 복습할 생각이다.

 

std::string::compare(...)

strcmp 라는 함수와 동일한 일을 하는 멤버 함수

현재 문자열 클래스의 문자열과 파라미터로 입력받은 문자열을 비교하여

같다면 0

현재 문자열 클래스가 우선순위가 높다면 1

파라미터로 받은 문자열 우선순위가 높다면 2를 리턴한다.

 

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>

int main() {
	std::string str1 = "apple";
	std::string str2 = "banana";

	if (str1.compare(str2) == 0) {
		printf("두 문자열은 같습니다");
	}
	else {
		printf("두 문자열은 다릅니다");
	}

	return 0;
}

이러면 else 구문에 있는 '두 문자열은 다릅니다' 가 출력이 된다.

 

둘 다 apple이면 같다고 나온다. 한 번 banana를 apple로 바꿔보고 실행해보자.

 

std

std를 계속 썼는데 std는 뭐냐하면 standard라는 뜻이다.

 

namespace

프로그래머끼리 같은 이름을 사용하지 않도록 이름들을 구분해주는 역할을 하는 개념

 

이 namespace는 Java에서는 package로 불리며, C#에서는 동일하게 namespace라고 부른다.

 

사용법은 간단하다

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>

namespace lee {
	void foo() {
		printf("혜성씨가 만든 함수 foo");
	}
}

namespace dang {
	void foo() {
		printf("당혜성이 만든 함수 foo");
	}
}

int main() {
	lee::foo();
	dang::foo();

	return 0;
}

 

그리고 선언과 몸체를 분리할 수 있다.

예시 코드

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>

namespace lee {
	void foo();
}

namespace dang {
	void foo();
}

int main() {
	lee::foo();
	dang::foo();

	return 0;
}

void lee::foo() {
	printf("혜성씨가 만든 foo");
}

void dang::foo() {
	printf("혜성씨가 만든 foo");
}

사실 namespace를 공부할때 사용하고 딱히 사용할 일이 없다.

 

사용 하는 사람들은 엔드급개발자 정도이다.

 

근데 요즘도 깃허브 같은걸로 다 충돌 하는지 안하는지 보면서 하기 때문에 굳이굳이이다.

 

그리고 std는 생략이 가능하다.

 

위에 include 밑에 using namespace std; 를 적어주면 된다.

 

class도 가능하다.

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>

using namespace std;

namespace lee {
	void foo();

	class marine {
	public:
		void printinfo(int i, const char* c) {

		}
		
	};
}

int main() {
	


	return 0;
}

lee::marine::marine() {

}

void lee::marine::printinfo(int i, const char* c) {

}

대충 이렇게 사용한다.

 

레퍼런스(Reference) 타입

파라미터를 받을때 타입 오른쪽에 &(앰퍼샌드)기호를 이용하게 되면 파라미터를 레퍼런스 타입으로 받을 수 있게 된다.

 

이 레퍼런스 타입은 파라미터로 일어나는 값 복사를 막아주어 실행할 수 있는 장점이 있다.

 

값을 스왑해 주는 코드가 있다.

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>

using namespace std;
void swap(int a, int b) {
	int temp;
	temp = a;
	a = b;
	b = temp;
}

int main() {
	int v1 = 100;
	int v2 = 200;

	swap(v1, v2);
	printf("v1:%d\nv2:%d", v1, v2);

	return 0;
}

이렇게 실행하면 값이 안바뀐다 라고 전에 강의에 있다.

 

이것을 해결하기 위한것은 포인터를 넣어 사용할 수 있고, 

 

다른 하나는 &를 넣어서 한다.

 

&를 넣으면 *를 안적어도 된다.

 

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>

using namespace std;
void swap(int& a, int& b) {
	int temp;
	temp = a;
	a = b;
	b = temp;
}

int main() {
	int v1 = 100;
	int v2 = 200;

	swap(v1, v2);
	printf("v1:%d\nv2:%d", v1, v2);

	return 0;
}

변수를 그대로 가져온다고 보면 된다.

 

std::string도 똗같다.

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>

using namespace std;
void swap(std::string& a, std::string & b) {
	std::string temp;
	temp = a;
	a = b;
	b = temp;
}

int main() {
	std::string v1 = "hi";
	std::string v2 = "bye";

	swap(v1, v2);
	printf("v1:%s\nv2:%s", v1.c_str(), v2.c_str());

	return 0;
}

이렇게 사용하면 값복사를 최소로 사용하게 된다.

 

파라미터를 사용하면 값을 복사해서 넣어주는건데, 이게 사소해 보이지만 문자열이 길어질수록 값이 나오는데 길어질 수 있다.

 

상당히 중요한 내용이다.

 

만약 10만번을 실행한다고 하자.

 

파라미터에 &를 사용하지 않은 코드

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>
#include <ctime>
using namespace std;
void swap(std::string a, std::string b) {
	std::string temp;
	temp = a;
	a = b;
	b = temp;
}

int main() {
	std::string v1 = "hi";
	std::string v2 = "bye";
	
	float start = clock();
	for (int i = 0; i < 100000; i++) {
		swap(v1, v2);
	}
	float end = clock();

	float time = (end - start) / CLOCKS_PER_SEC;
	printf("경과 시간%f", time);
	//printf("v1:%s\nv2:%s", v1.c_str(), v2.c_str());

	return 0;
}

 

파라미터에 &붙인 코드

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>
#include <ctime>
using namespace std;
void swap(std::string& a, std::string& b) {
	std::string temp;
	temp = a;
	a = b;
	b = temp;
}

int main() {
	std::string v1 = "hi";
	std::string v2 = "bye";
	
	float start = clock();
	for (int i = 0; i < 100000; i++) {
		swap(v1, v2);
	}
	float end = clock();

	float time = (end - start) / CLOCKS_PER_SEC;
	printf("경과 시간%f", time);
	//printf("v1:%s\nv2:%s", v1.c_str(), v2.c_str());

	return 0;
}

 

아마 둘이 실행하면 실행하면 시간이 꽤나 많이 차이가 난다.