C++/C++ 기초

[C++] 기본 입출력 ( 화면 출력 / 키 입력받기 / 문자열 입력받기 )

Song 컴퓨터공학 2023. 7. 2. 19:32

[목차]

1. 화면 출력

2. 키 입력 받기 (cin)

3. 문자열 입력 받기


 화면 출력 - cout 과 << 연산자 사용

 

C++ 에서는 cout과 << 연산자를 이용해 문자열 뿐만 아니라 다양한 데이터를 화면에 출력합니다.

cout 은 스크린 장치와 연결된 C++ 표준 출력 스트림 객체(Standard output stream object) 로, <iostream>의 std namespace 에 속해 있기 때문에 using namespace std; 를 사용하지 않는다면 std:: 를 붙여줘야 합니다.

// cout 과 << 를 이용한 화면 출력
#include <iostream>

double area(int r);

double area(int r){
	return 3.14*r*r;
}

int main(){
	int n = 3;
	char c = '#';
	std::cout << c << 5.5 << '-' << n << "hello" << true << std::endl;
	std::cout << "n+5 = " << n+5 << '\n';
	std::cout << "면적은 " << area(n);
}

<< 연산자는 스트림 삽입 연산자(Stream insertion operator) 라고 불리며 오른쪽 피연산자 데이터를 왼쪽 스트림 객체에 삽입합니다. 원래 << 연산자는 왼쪽 비트 시프트 연산자로 C에서 배웠습니다. C++ 에서도 이 연산자는 똑같은 역할도 수행합니다. 그런데도 cout 과 함께 사용할 때 스트림 삽입 연산자로 동작하는 것은 <iostream> 헤더 파일에 재정의, operator overloading 되어 있기 때문입니다. 연산자 overloading 은 차후에 다시 다뤄보도록 할 건데, 우선은 연산자가 적용되는 상황에 따라 여러 역할을 수행한다. 고 이해하시면 됩니다.

 

<< 연산자는 문자열뿐 아니라 C++ 에서 제공하는 boo, char, short, int, long, float, double 같은 C++ 기본 데이터 타입도 출력할 수 있습니다. 또한 함수를 그대로 써놔 리턴값을 바로 출력할 수도 있습니다.

#include <iostream>
using namespace std;

namespace Graphic {
	int maximum = 100;
}
namespace Math {
	int maximum = 65536;
	int add(int a, int b) { return a + b; }
	int sub(int a, int b) { return a - b; }
}

int main()
{
	cout << "Radius Maximum = " << Graphic::maximum << endl;
	cout << "Integer Maximum = " << Math::maximum << endl;
	cout << "Interger Add = " << Math::add(2, 4) << endl;
}

위에서 일부러 다양한 예시를 위해 2개의 namespace 를 사용해 cout과 << 를 이용해 출력해보았죠. 클래스 등의 이름(identifier)가 충돌하는 것을 막기 위해, 개발자가 자신만의 고유한 이름 공간을 생성할 수 있도록 C++에서는 namespace 키워드를 제공합니다. 

namespace song {
	...
}

song :: identifier

namespace 키워드와 중괄호를 통해 namespace 를 생성할 수 있고, 이를 접근할 때는 범위 지정 연산자 :: 를 사용해 접근합니다. :: 는 scope 연산자 라고 주로 부릅니다.

 

 

 

 키 입력 받기 - cin 과 >> 연산자 사용

 

표준 입력 스트림(Standard input stream object)인 cin >> 연산자(스트림 추출 연산자) 로 키를 입력받을 수 있습니다. cout << 와 마찬가지로 모든 기본 타입의 데이터에 대해 >> 연산자로 데이터 입력이 가능합니다. C언어에서는 scanf 같은 함수를 사용할 때 & 연산자를 통해 변수의 주소를 넘겨주거나 하는 복잡한 과정이 있었지만 C++ 에서는 그럴 필요 없이 선언한 변수 그대로를 써주면 입력 받아 바로 저장해줍니다. 훨씬 편리한거죠.

#include <iostream>
using namespace std;

int main()
{
	int width;
	int height;
	cout << "너비와 높이를 입력하세요 : ";
	cin >> width >> height;
	cout << "넓이 : " << width * height << endl;
}

입력을 통해 유추할 수 있듯 cin 은 여러 개의 >> 연산자를 이용해 여러 값을 입력 받을 수도 있습니다. >> 연산자들은 왼쪽부터 오른쪽으로 순서대로 키보드로부터 입력 받고, "공백"을 기준으로 구분하여 데이터를 받습니다.

 

그런데 cin 과 >> 연산자는 어떤 것을 기준으로 사용자의 키 입력이 끝났음을 알고 그를 저장할까요? 왜 두번째 데이터는 1이 아니라 10이 정확히 전달되었을까요? 그것은 cin과 >> 연산자는 <Enter> 키를 통해 사용자의 입력이 끝났다고 인식하기 때문입니다.

 

사용자가 입력한 키들은 곧바로 변수에 저장되는 것이 아니라 cin의 스트림 버퍼에 저장되며, <Enter> 키가 입력되면 비로서 >> 연산자가 cin의 스트림 버퍼에서 키 값을 끌어내어 변수에 저장합니다. <Enter> 키를 누르는 순간 >> 연산자가 동작합니다.

 

 

 

 문자열 입력 받기 - cin.getline() 이용 : 배열로 문자열 저장하는 경우

 

cin 을 이용해 문자열을 입력받는 점은 한계가 있습니다. 왜냐면 "공백"을 기준으로 구분하기 때문에 공백을 만나면 문자열의 입력이 종료된 것으로 인식하기 때문입니다.

#include <iostream>
using namespace std;

int main()
{
	char word[100];
	for (int i = 0; i < 2; i++) {
		cout << "문자열를 입력하세요 : ";
		cin >> word;
		cout << word << endl;
	}
}

 

따라서 이렇게 배열을 이용해 문자열을 저장하는 경우, cin이 아닌 전체 라인을 읽는 cin 객체의 getline() 멤버 함수를 이용해야 공백이 포함된 문자열을 입력받을 수 있습니다.

cin.getline(char buf[], int size, char delimitChar)
buf : 키보드로부터 읽은 문자열을 저장할 배열
size : buf[] 배열의 크기
delimitChar : 문자열 입력 끝을 지정하는 구분문자

최대 size-1 개의 문자를 입력받거나 delimitChar 로 지정한 구분 문자를 만날 때까지 공백 문자를 포함해 문자열을 입력받는 멤버 함수입니다. 

#include <iostream>
using namespace std;

void main()
{
	cout << "주소를 입력하세요 >>";

	char address[100];
	cin.getline(address, 100, '\n');
	cout << "주소는 " << address << "입니다" << endl;
}

따라서 위처럼 배열을 사용해 문자열을 저장하는 경우에는 cin 객체의 getline 멤버함수를 사용합니다.

 

 

 

 문자열 입력 받기 - getline() 을 이용 : string 객체 사용하는 경우

cin 객체의 getline() 멤버함수를 사용하는 배열에 문자열을 저장하는 방식은 배열의 크기에 의해 문자열의 크기가 제한되는 단점이 있지만, C++ 의 string 객체를 사용하면 문자열의 크기에 제약이 없게 사용할 수 있습니다. string 객체는 마치 동적배열처럼 문자열의 길이가 길어지더라도 그 만큼의 추가적인 메모리를 할당받아 사용하기 때문입니다.

 

또한 string 클래스를 이용하는 방법은 객체지향적일 뿐 아니라 문자열을 다루기도 쉬우니 C++에서는 문자열을 배열로 다루는 것보다 string 객체로 다루는 것이 바람직합니다. C에서 주구장창 배웠던 strcpy, strcat 등등을 훨씬 쉽게 다룰 수 있습니다. string 객체는 <string> 헤더파일에 선언되어 있기 때문에 이용하기 위해서는 추가적인 include 가 필요합니다.

 

string 객체를 사용해 문자열을 저장하는 경우, 표준 라이브러리에서 지원하는 getline(istream&, string&) 를 사용할 수 있습니다. getline(cin, 저장할 string) 을 통해 문자열을 입력받는 것이죠. 또한 이렇게 저장한 string 또한 배열처럼 인덱스를 통해 각 문자에 접근할 수 있습니다. 그리고 strcat 을 함수가 아닌 단지 + 연산을 통해서 뒤에 덧붙일 수도 있습니다.

#include <iostream>
#include <string>
using namespace std;

void main() {
	string song("Falling in love with you");
	string elvis("Elvis Presly");
	string singer;

	cout << song + "를 부른 가수는" << "(힌트 : 첫 글자는 " << elvis[0] << ")?";
	getline(cin, singer);
	if (singer == elvis)
		cout << "맞았습니다";
	else
		cout << "틀렸습니다." + elvis + "입니다." << endl;
}

이로부터 혼동을 할 수도 있는데요, + 연산은 오직 string 객체에 대해서만 사용가능합니다.

#include <iostream>
#include <string>
using namespace std;

int main() {
	string year = "2023";
	cout << year + "년" << endl;

	cout << 2022 + "년"; // 틀린 코드. + 연산자는 string 에서만 사용
}

저렇게 t 라는 쌩뚱맞은 값이 나오게 됩니다. 여기까지 C++ 기본 입출력 방법에 대해 알아보았습니다. 감사합니다.

 

참고 문헌 : 명품 C++ Programming