학습목표
- C++에서의 입출력
iostream
계열의 클래스- 리디렉션
ostream
클래스 메소드- 출력 형식 지정
istream
클래스 메소드- 스트림의 상태
- 파일 입출력
- 파일로부터 입력을 얻는
ifstream
클래스 - 파일에 출력을 하는
ofstream
클래스 - 파일 입출력을 위한
fstream
클래스 - 명령행 처리
- 2진 파일
- 파일 임의 접근
- 인코어 형식 지정
17.1 C++ 입출력의 개요
C++에서도 cstdio
헤더 파일을 통해 입출력에 사용하는 일반적인 C 함수들을 사용할 수 있음
C++ 스타일의 입출력은 iostream
, fstream
헤더 파일에 정의되어있는 클래스들의 집합을 사용함
스트림과 버퍼
C++에서는 입력과 출력을 바이트들의 흐름인 스트림으로 간주함
- 입력시 입력 스트림으로 바이트들을 추출, 출력시 출력 스트림에 바이트들을 삽입
- 바이트들은 수치 데이터 또는 문자의 2진 표현을 나타낼 수 있음
- 입력 스트림의 바이트들은 키보드 / 저장장치 / 다른 프로그램으로부터 흘러나올 수 있음
- 출력 스트림의 바이트들은 디스플레이 / 프린터 / 저장장치 / 다른 프로그램으로 흘러나갈 수 있음
입력을 다루기 위해선 두가지 절차가 필요
- 하나의 스트림을 프로그램의 입력에 연결
- 스트림을 하나의 파일에 연결
- 즉, 입력 스트림은 양쪽에 하나씩 두개의 연결을 필요로함
버퍼 이용시 입력과 출력을 더 효율적으로 처리할 수 있음
- 버퍼(buffer) : 정보를 전송하기 위해 임시 저장장치로 사용하는 메모리 블록
- 저장장치와 프로그램의 정보 전송률 차이를 극복할 수 있도록 도와줌
- 우선 버퍼에 한꺼번에 많은 데이터를 읽어들여 저장한 후, 이후 프로그램이 버퍼로부터 데이터를 읽어들임
- 출력시 버퍼를 가득 채운 다음 전송하고, 이후 버퍼를 깨끗하게 비우는 버퍼 비우기(flushing the buffer)를 수행함
- 일반적으로 사용자가
Enter
를 누를때 입력 버퍼를 비우고, 개행 문자를 전달받으면 출력 버퍼를 비움
스트림, 버퍼, iostream 파일
C++에서의 입출력 클래스
streambuf
클래스 : 버퍼로 사용할 메모리 제공, 버퍼 채우기, 버퍼 접근, 버퍼 비우기 등 버퍼 메모리를 관리하는 클래스 메소드 제공ios_base
클래스 : 스트림의 일반적인 특성들을 나타냄ios
클래스 :ios_base
클래스에 기초하며streambuf
객체를 지시하는 포인터 멤버를 가짐ostream
클래스 :ios
클래스에서 파생되어 출력 메소드들을 제공istream
클래스 :ios
클래스에서 파생되어 입력 메소드들을 제공iostream
클래스 :istream
클래스와ostream
클래스에 기초하여 입력 메소드들과 출력 메소드들을 모두 상속받음
프로그램에 iostream
파일 포함시 자동으로 8개의 스트림 객체가 생성됨
cin
: 표준 입력 스트림에 해당, 키보드 등의 표준 입력 장치에 연결됨cout
: 표준 출력 스트림에 해당, 모니터 등의 표준 출력 장치에 연결됨cerr
: 표준 에러 스트림에 해당, 표준 출력 장치에 연결되나 버퍼를 사용하지 않기 때문에 곧바로 출력됨clog
: 표준 에러 스트림에 해당, 표준 출력 장치에 연결되며 버퍼를 사용함wcin
,wcout
,wcerr
,wclog
:wchar_t
형에 동작
스트림이 해당하는 객체 생성시 해당 객체는 입력 또는 출력과 관련된 모든 정보를 담고있는 데이터 멤버들을 가지게됨
리디렉션
리디렉션(redirection) : 표준 입력과 표준 출력을 위한 연결을 다른쪽으로 변경
많은 운영체제들이 리디렉션 기능을 지원함
cout
으로 나타나는 표준 출력 스트림, cerr
와 clog
로 나타나는 표준 에러 스트림의 객체들은 모두 모니터로 보내짐
표준 출력을 리디렉션하는 것은 cerr
와 clog
에 영향을 주지 않기 때문에 cout
출력이 다른 곳으로 리디렉션되어있는 경우에도 에러 메시지를 화면에 출력함
운영체제에 따라 표준 에러를 리디렉션할 수 있는 경우도 있음
17.2 cout을 이용한 출력
ostream
클래스는 int
나 float
와 같은 수치 데이터를 문자들의 스트림으로 변환함
즉, 2진 비트 패턴으로 되어있는 수치 데이터의 내부적인 표현을 문자 바이트의 스트림으로 변환함
오버로딩된 << 연산자
ostream
클래스는 오버로딩을 통해 기본적으로 왼쪽 시프트 연산자로 사용되는 <<
연산자를 ostream
클래스에 대한 출력으로 재정의함
- 이 경우의
<<
연산자는 삽입 연산자라고 부름 - 삽입 연산자는 C++의 모든 기본 데이터형들을 인식할 수 있도록 오버로딩되어있음
- 각각의 데이터형들에 대해
operator<<()
함수 정의를 제공함
ostream
클래스는 포인터형을 위한 삽입 연산자 함수들도 정의함
const signed char *
,const unsigned char *
,const char *
,void *
- 따라서
char * pn = "abc"; cout << pn;
구문은 정상적으로 작동함 - 다른 데이터형을 지시할 경우 포인터를
void *
형에 일치시킨 후 그 주소의 수치적 표현을 출력함
모든 삽입 연산자 함수들은 ostream &
형을 리턴하도록 정의되어있음
- 리턴하는 참조는 연산자를 호출한 객체에 대한 참조임
- 따라서 이를 이용하여 출력을 연이어 할 수 있음
그 밖의 ostream 메소드들
ostream
클래스는 문자들을 화면에 출력하는 put()
메소드와 write()
메소드를 제공함
put()
메소드도 호출한 객체에 대한 참조를 리턴하므로 연이어 출력할 수 있음put()
메소드에 적절한 수치형 매개변수 사용시char
형 값으로 변환하여 사용됨write()
메소드는 전체 문자열을 출력하며, 첫번째 매개변수로 출력할 문자열의 주소를 받고 두번째 매개변수로 출력할 문자들의 수를 받음
// write.cpp
#include <iostream>
#include <cstring>
int main()
{
using std::cout;
using std::endl;
const char * state1 = "Florida";
const char * state2 = "Kansas";
const char * state3 = "Euphoria";
int len = std::strlen(state2);
cout << "루프 인덱스 증가 : \n";
int i;
for (i = 1; i <= len; i++)
{
cout.write(state2, i);
cout << endl;
}
cout << "루프 인덱스 감소 : \n";
for (i = len; i > 0; i--)
cout.write(state2, i) << endl;
cout << "문자열 길이 초과 : \n";
cout.write(state2, len + 5) << endl;
return 0;
}
cout.write()
호출은 그것을 호출한 객체에 대한 참조를 리턴함 write()
메소드는 널문자에 도달하더라도 출력을 자동으로 멈추지 않음 write()
메소드는 수치 데이터에도 사용할 수 있으며, 따라서 char *
형으로 캐스트한 어떤 수의 주소를 전달할 수 있음
- 이 때 수치를 값에 해당하는 문자로 변환하는 것이 아니라 메모리에 저장된 비트 표현을 그대로 전달함
- 수치 데이터를 가장 간결하고 정확하게 파일에 저장하는 방법을 제공함
출력 버퍼 비우기
cout
객체가 다루는 출력에는 버퍼를 사용하므로 출력은 버퍼가 가득 찰 때까지 쌓임
이후 버퍼의 내용을 목적지로 보내고 새로운 데이터 저장을 위해 버퍼를 깨끗하게 배움
단, 메모리 낭비를 방지하기 위해 개행 문자를 보낼시 버퍼가 자동으로 비워짐
긴급 입력을 받아들여야할 때도 버퍼를 비우기 때문에 문자열에 개행 문자가 들어있지 않더라도 그 뒤의 입력을 예상하여 문자열을 즉시 출력할 수 있음
사용자가 원하는 때에 출력이 되지 않을시 조정자(manipulator)를 사용하여 강제로 출력할 수 있음
flush
: 버퍼를 비움endl
: 버퍼를 비우고 개행 문자를 삽입함- 조정자들은 실제로는
<<
연산자로 오버로딩되는 함수이기 때문에 직접 호출하는 것도 가능함
cout을 이용한 출력 형식 지정
ostream
삽입 연산자는 값들을 텍스트 형식으로 변환함
- 인쇄할 수 있는 문자에 해당하는
char
형 값은 한 문자 필드 폭에 해당 문자를 출력함 - 수치 정수형은 알맞은 크기의 필드 폭에 십진수 형식으로 출력하며, 음수인 경우 마이너스 부호도 함께 출력함
- 문자열은 해당 문자열 길이에 맞는 크기의 필드폭에 출력함
- 부동 소수점형은 총 6자리에 출력되며 뒤에 붙는 0들은 출력되지 않고, 지수가 6 이상이거나 -5 이하면 E 표기가 사용됨
// defaults.cpp
#include <iostream>
int main()
{
using std::cout;
cout << "12345678901234567890\n";
char ch = 'K';
int t = 273;
cout << ch << " : \n";
cout << t << " : \n";
cout << -t << " : \n";
double f1 = 1.200;
cout << f1 << " : \n";
cout << (f1 + 1.0 / 9.0) << " : \n";
double f2 = 1.67E2;
cout << f2 << " : \n";
f2 += 1.0 / 9.0;
cout << f2 << " : \n";
cout << (f2 * 1.0e4) << " : \n";
double f3 = 2.3e-4;
cout << f3 << " : \n";
cout << f3 / 10 << " : \n";
return 0;
}
화면 출력을 위한 진법 변경
조정자를 사용하여 화면에 정수를 출력할 때 사용되는 진법을 제어할 수 있음
출력 상태를 서술하는 정보를 가지고 있는 ios_base
의 멤버 함수를 사용하여 필드 폭과 소수점 아래 자릿수를 제어할 수 있음
// manip.cpp
#include <iostream>
int main()
{
using namespace std;
cout << "하나의 정수를 입력하십시오 : ";
int n;
cin >> n;
cout << "n\tn*n\n";
cout << n << "\t" << n*n << " (10진법)\n";
cout << hex;
cout << n << "\t";
cout << n*n << " (16진법)\n";
cout << oct << n << "\t" << n*n << " (8진법)\n";
dec(cout);
cout << n << "\t" << n*n << " (10진법)\n";
return 0;
}
필드 폭 조정
width()
멤버 함수를 사용하여 서로 다른 크기의 수들을 동일한 필드 폭에 출력할 수 있음
int width();
의 경우 현재 설정된 필드 폭을 리턴함int width(int i);
의 경우 현재 필드 폭을 i칸으로 설정하고 이전의 필드 폭을 리턴함- 바로 다음에 출력될 항목에만 영향을 미친 후 해당 항목을 지나가면 디폴트 값으로 환원됨
// width.cpp
#include <iostream>
int main()
{
using std::cout;
int w = cout.width(30);
cout << "디폴트 필드 폭 = " << w << " : \n";
cout.width(5);
cout << "N" << ':';
cout.width(8);
cout << "N * N" << ":\n";
for (long i = 1; i <= 100; i *= 10)
{
cout.width(5);
cout << i << ':';
cout.width(8);
cout << i*i << " : \n";
}
return 0;
}
채움 문자
기본적으로 cout
은 필드 폭의 남는 부분을 빈칸으로 채우며, fill()
멤버 함수를 사용하면 다른 것으로 바꿀 수 있음
// fill.cpp
#include <iostream>
int main()
{
using std::cout;
cout.fill('*');
const char * staff[2] = {"윤성일", "박순용"};
long bonus[2] = {900, 1350};
for (int i = 0; i < 2; i++)
{
cout << staff[i] << " : $";
cout.width(7);
cout << bonus[i] << "\n";
}
return 0;
}
부동 소수점수의 출력 정밀도 설정
부동 소수점수의 정밀도의 경우
- 디폴트 모드에서는 출력되는 총 자릿수를 의미
- 고정 소수점 표기 또는 지수 표기 모드에서는 소수점 아래 자릿수를 의미
precision()
이라는 멤버 함수를 사용하여 정밀도를 다르게 설정할 수 있음
// precise.cpp
#include <iostream>
int main()
{
using std::cout;
float price1 = 20.40;
float price2 = 1.9 + 8.0 / 9.0;
cout << "\"손오공 인형\" $" << price1 << "!\n";
cout << "\"사오정 인형\" $" << price2 << "!\n";
cout.precision(2);
cout << "\"손오공 인형\" $" << price1 << "!\n";
cout << "\"사오정 인형\" $" << price2 << "!\n";
return 0;
}
뒤에 붙는 0과 소수점 출력
ios_base
클래스의 setf()
함수에서 여러가지 설정이 가능함 ios_base::showpoint
는 cout
이 뒤에 붙는 소수점을 출력하도록 만들며, 디폴트 부동 소수점 형식에서 뒤에 붙는 0들도 출력하게 만듬
// showpt.cpp
#include <iostream>
int main()
{
using std::cout;
using std::ios_base;
float price1 = 20.40;
float price2 = 1.9 + 8.0 / 9.0;
cout.setf(ios_base::showpoint);
cout << "\"손오공 인형\" $" << price1 << "!\n";
cout << "\"사오정 인형\" $" << price2 << "!\n";
cout.precision(2);
cout << "\"손오공 인형\" $" << price1 << "!\n";
cout << "\"사오정 인형\" $" << price2 << "!\n";
return 0;
}
setf()에 대한 보충
setf()
가 정의되어있는 ios_base
클래스는 하나의 protected
멤버를 가지고있으며, 해당 멤버의 각 비트들은 진법이나 뒤에붙는 0들의 출력 여부 등을 제어함
이 비트들을 키는 것(=1로 설정)을 플래그를 설정한다고 함
첫번째 원형은 fmtflags setf(fmtflags);
의 형태를 가지며, fmtflags
는 출력 형식 플래그를 보관하는데 사용되는 비트마스크(bitmask) 데이터형의 typedef
이름으로 ios_base
에 정의되어있음
- 매개변수는 설정할 비트를 나타내며, 모든 플래그들이 이전 설정값을 나타내는
fmtflags
형 수를 리턴함 boolalpha
,showbase
,showpoint
,uppercase
,showpos
등의 지정 상수들이 존재함- 출력 형식 지정 상수들은
ios_base
클래스에 정의되어있으므로 사용 범위 결정 연산자와 함께 사용해야함
// setf.cpp
#include <iostream>
int main()
{
using std::cout;
using std::endl;
using std::ios_base;
int temperature = 63;
cout << "오늘의 수온 : ";
cout.setf(ios_base::showpos);
cout << temperature << endl;
cout << "프로그래머들에게 그 값은\n";
cout << std::hex << temperature << endl;
cout.setf(ios_base::uppercase);
cout.setf(ios_base::showbase);
cout << "또는\n";
cout << temperature << endl;
cout << true << "!의 값은 ";
cout.setf(ios_base::boolalpha);
cout << true << "이다.\n";
return 0;
}
두번째 원형은 fmtflags setf(fmtflags, fmtflags);
의 형태를 가짐
- 첫번째 매개변수는 원하는 설정이 담긴
fmtflags
값을 사용 - 두번째 매개변수는 해당 비트들을 먼저 깨끗하게 지우는 값을 사용
basefield
- 진법 변경,floatfield
- 표기 변경,adjustfield
- 정렬 변경
// setf2.cpp
#include <iostream>
#include <cmath>
int main()
{
using namespace std;
cout.setf(ios_base::left, ios_base::adjustfield);
cout.setf(ios_base::showpos);
cout.setf(ios_base::showpoint);
cout.precision(3);
ios_base::fmtflags old = cout.setf(ios_base::scientific, ios_base::floatfield);
cout << "왼쪽 정렬 : \n";
long n;
for (n = 1; n <= 41; n += 10)
{
cout.width(4);
cout << n << "|";
cout.width(12);
cout << sqrt(double(n)) << "|\n";
}
cout.setf(ios_base::internal, ios_base::adjustfield);
cout.setf(old, ios_base::floatfield);
cout << "내부(internal) 정렬 : \n";
for (n = 1; n <= 41; n += 10)
{
cout.width(4);
cout << n << "|";
cout.width(12);
cout << sqrt(double(n)) << "|\n";
}
cout.setf(ios_base::right, ios_base::adjustfield);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << "오른쪽 정렬 : \n";
for (n = 1; n <= 41; n += 10)
{
cout.width(4);
cout << n << "|";
cout.width(12);
cout << sqrt(double(n)) << "|\n";
}
return 0;
}
setf()
의 효과는 unsetf()
를 호출하여 취소시킬 수 있음
void unsetf(fmtflags mask);
형태의 원형을 가짐mask
는 하나의 비트 패턴으로mask
에 1로 설정되어있는 모든 비트들이 해당 비트들의 설정을 해제하여 0으로 만듬cout.setf(0, ios_base::floatfield);
와cout.unsetf(ios_base::floatfield);
는 동일함
표준 조정자
C++은 setf()
를 호출하는 몇가지 조정자를 제공하여 정확한 매개변수를 자동으로 호출함
boolalpha
,noboolalpha
showbase
,noshowbase
showpoint
,noshowpoint
showpos
,noshowpos
uppercase
,nouppercase
internal
,left
,right
dec
,hex
,oct
fixed
,scientific
iomanip 헤더 파일
출력 형식 지정시 iostream
의 도구들은 번거로울 수 있기 때문에, iomanip
헤더파일 안에 조정자들을 제공함
setprecision()
,setfill()
,setw()
함수 등이 있음- 매개변수를 사용하며,
cout
구문에 연결하여 사용할 수 있음
// iomanip.cpp
#include <iostream>
#include <iomanip>
#include <cmath>
int main()
{
using namespace std;
cout << fixed << right;
cout << setw(6) << "N" << setw(14) << "제곱근"
<< setw(15) << "네제곱근\n";
double root;
for (int n = 10; n <= 100; n += 10)
{
root = sqrt(double(n));
cout << setw(6) << setfill('.') << n << setfill(' ')
<< setw(12) << setprecision(3) << root
<< setw(14) << setprecision(4) << sqrt(root)
<< endl;
}
return 0;
}
17.3 cin을 이용한 입력
cin
객체는 표준 입력을 바이트들의 스트림으로 나타냄
일반적으로 문자들의 스트림은 키보드로 발생하며, 입력 스트림으로부터의 추출은 데이터형 변환을 포함 cin
이 입력을 해석하는 방법은 주어지는 데이터형에 따라 달라지고 기본 데이터형들을 인식할 수 있도록 istream
클래스에 추출 연산자 >>
가 오버로딩되어있음
- 입력 데이터를 목적지가 지시하는 데이터형으로 변환하므로 형식이 설정된 입력함수(formatted input function) 이라고 부름
istream & operator>>(int &);
의 원형을 가짐- 매개변수가 참조이므로 매개변수로 사용된 변수의 값을 직접 변경할 수 있음
- 호출한 객체의 참조를 리턴하기 때문에 입력도 연이어 할 수 있음
cin
에hex
,oct
,dec
조정자를 함께 사용할 수 있음- 문자 포인터형들에 대한 오버로딩된
>>
연산자는 입력 스트림으로부터 단어를 읽은 후 널 문자를 덧붙임
cin >>은 입력을 어떻게 보는가?
추출 연산자들은 모두 동일한 방법으로 입력 스트림을 확인함
- 화이트스페이스가 아닌 문자가 나올때까지 화이트스페이스를 건너뜀
- 즉, 화이트스페이스가 아닌 최초의 문자에서 시작하여 원하는 데이터형과 일치하지 않는 첫 번째 문자에 도달할때까지의 문자들을 읽음
- 입력이 프로그램이 기대하는 것과 다른 경우 추출 연산자는 변수의 값을 변경하지 않고 0을 리턴함
// check_it.cpp
#include <iostream>
int main()
{
using namespace std;
cout << "수를 입력하십시오 : ";
int sum = 0;
int input;
while (cin >> input)
sum += input;
cout << "마지막으로 입력한 값 = " << input << endl;
cout << "합계 = " << sum << endl;
return 0;
}
스트림 상태
cin
, cout
객체는 스트림 상태(stream state)를 나타내는 하나의 데이터 멤버(ios_base 클래스로부터 상속된)를 가지고있음 iostate
형으로 정의되어있는 스트림 상태는 eofbit
, badbit
, failbit
라는 세 개의 ios_base
원소로 구성됨
- 각 원소는 1(설정) 또는 0(해제)이 될 수 있는 단일 비트
cin
연산이 파일의 끝에 도달한경우eofbit
를 설정cin
연산이 기대하는 문자를 읽지 못한경우failbit
를 설정- 접근할 수 없는 파일 읽기 / 쓰기 방지된 디스크에 쓰다가 입출력 실패가 발생한 경우에도
failbit
를 설정 - 알 수 없는 원인으로 스트림이 손산되었을 경우
badbit
를 설정
이외에도 상태 비트와 스트림 상태를 보고하거나 변경하는 ios_base
메소드들이 존재함
good()
: 스트림을 사용할 수 있으면true
를 리턴하고 모든 비트를 해제eof()
:eofbit
가 설정되면true
를 리턴bad()
:badbit
가 설정되면true
를 리턴fail()
:badbit
나failbit
가 설정되면true
를 리턴rdstate()
: 스트림 상태를 리턴exceptions()
: 예외를 발생시킨 플래그를 식별하는 비트마스크를 리턴exceptions(iostate ex)
:clear()
를 통해 예외를 발생시킬 상태를 설정clear(iostate s)
: 스트림 상태를 s로 설정하며, s의 디폴트는 0임setstate(iostate s)
:clear(rdstate() | s)
를 호출하여 스트림 상태 비트를 s에 설정된 해당 비트로 설정함
상태 설정
clear()
메소드는 상태를 해당 매개변수로 설정
clear();
는 디폴트 매개변수인 0으로eofbit
,badbit
,failbit
를 모두 해제clear(eofbit);
는 상태를eofbit
와 동등하게 만들어 나머지 비트를 해제함
setstate()
메소드는 해당 매개변수에 설정되어있는 비트에만 영향을 줌
setstate(eofbit);
는eofbit
만 설정하고 나머지 비트에 영향을 주지 않음- 입력 및 출력, 함수를 통해 상태를 변경할 수 있는 수단을 제공
입출력과 예외
exceptions()
메소드는 eofbit
, failbit
, badbit
3가지 비트를 가지고있는 하나의 비트 필드를 리턴함 clear()
메소드로 스트림 상태가 바뀐 뒤엔 현재의 스트림 상태가 exceptions()
가 리턴하는 값과 비교됨
이 때 리턴값과 현재 스트림 상태에 같은 비트가 설정되어있을시 clear()
는 basic_ios::failure
예외를 발생시키며, 이는 std::exception
클래스로 파생되어 what()
메소드를 가지고있음
exceptions()
의 디폴트 설정은 goodbit
이기 때문에 예외가 발생하지 않음
이는 오버로딩된 exceptions(iostate)
함수를 사용하여 제어할 수 있음
// cinexcp.cpp
#include <iostream>
#include <exception>
int main()
{
using namespace std;
cin.exceptions(ios_base::failbit);
cout << "수를 입력하십시오 : ";
int sum = 0;
int input;
try {
while (cin >> input)
sum += input;
} catch(ios_base::failure & bf)
{
cout << bf.what() << endl;
cout << "앗! 실수!\n";
}
cout << "마지막으로 입력한 값 = " << input << endl;
cout << "합계 = " << sum << endl;
return 0;
}
스트림 상태 효과
if
나 while
은 cin
으로 리턴된 객체의 스트림 상태가 양호한 경우에만 true
로 평가함
스트림 상태 비트가 설정된 후에는 해당 비트가 해제될 때까지 추가 입력 및 출력에 대해 스트림이 닫힘
이를 good
상태로 재설정하여 추가 입출력을 하고자한다면 clear()
메소드를 호출하여 해결함
단, 불량 입력이 입력 큐에 남아있는 경우 화이트스페이스에 도달할 때까지 계속해서 문자를 읽을 수 있음
입력이 파일 끝이나 하드웨어적 장애 때문에 종료되었을 시 fail()
메소드를 사용하여 문제를 해결할 수 있음 fail()
은 failbit
또는 eofbit
둘 중 하나라도 설정될시 true
를 리턴하므로 eofbit
를 배제해야하는 경우가 생길 수 있음
그 밖의 istream 클래스 메소드들
get(char &)
와 get(void)
메소드는 화이트스페이스를 건너뛰지 않는 단일 문자 입력 기능을 제공 get(char *, int, char)
와 getline(char *, int, char)
함수는 기본적으로 행 전체를 읽어들이는 입력 기능을 제공 get()
과 getline()
은 단순히 문자 입력만 받아들이기 때문에 형식이 설정되지 않은 입력 함수(unformatted input function)이라고 부름
단일 문자 입력
get()
메소드는 다음 입력 문자가 무엇이든간에 해당 문자를 입력받음
get(char &)
의 경우 입력 문자를 매개변수에 대입함
- 자신을 호출하는데 사용된
istream
객체에 대한 참조를 리턴하기 때문에 연이어 표기할 수 있음 - 실제 또는 키보드에서 만들어진 파일의 끝을 만나더라도 매개변수에 값을 전달하지 않으며,
setstate(failbit)
를 호출하여cin
이false
로 평가되게 만듬
get(void)
의 경우 입력 문자를 정수형으로 변환하여 리턴값으로 사용
- 리턴값이 객체가 아니므로 멤버 연산자를 적용시킬 수 없음
- 실제 또는 시뮬레이트된 파일의 끝에 도달할 경우
iostream
에 정의된 상수기호인EOF
를 리턴함
화이트스페이스를 건너뛸경우 >>
추출 연산자를 사용
프로그램이 모든 문자를 검사해야한다면 get()
메소드를 사용
문자열 입력 : getline(), get(), ignore()
getline()
과 get()
의 첫번째 매개변수는 입력 문자열을 저장할 메모리의 주소를, 두번째 매개변수는 최대 허용 문자 수 + 1을 나타내고 세번째 매개변수는 입력에 구획 문자로 사용할 문자로 지정
세번째 매개변수가 없을 경우엔 개행 문자를 구획 문자로 사용함
단, get()
은 입력 스트림에 개행 문자를 남겨두고 getline()
은 버림
ignore()
는 최대 허용 문자 수 또는 개행 문자를 만날 때까지 문자를 읽고 바로 버림
istream & ignore(int = 1, int = EOF);
의 원형을 가짐- 호출한 객체를 리턴하므로 연이어 사용할 수 있음
// get_fun.cpp
#include <iostream>
const int Limit = 255;
int main()
{
using std::cout;
using std::cin;
using std::endl;
char input[Limit];
cout << "getline()이 처리할 문자열을 입력하십시오 : \n";
cin.getline(input, Limit, '#');
cout << "다음과 같이 입력하셨습니다 : \n";
cout << input << "\n1단계 완료\n";
char ch;
cin.get(ch);
cout << "다음 입력 문자는 " << ch << "입니다" << endl;
if (ch != '\n')
cin.ignore(Limit, '\n');
cout << "get()이 처리할 문자열을 입력하십시오 : \n";
cin.get(input, Limit, '#');
cout << "다음과 같이 입력하셨습니다 : \n";
cout << input << "\n2단계 완료\n";
cin.get(ch);
cout << "다음 입력 문자는 " << ch << "입니다" << endl;
return 0;
}
기대하지 않는 문자열의 입력
get(char *, int)
와 getline()
는 다른 입력 함수들과 마찬가지로 파일 끝을 만나면 eofbit
를, 스트림이 손상될경우 badbit
를 설정함
어떠한 문자도 성공적으로 추출하지 못한 경우 입력 문자열에 널문자를 넣고 setstate()
를 failbit
로 설정
- 입력 메소드가 곧바로 파일 끝을 만났을 때,
get(char *, int)
의 경우 빈 줄을 입력했을 때 해당 상황이 발생 getline()
은 개행문자를 저장하지 않더라도 추출하기 때문에 빈 줄을 입력받아도failbit
를 설정하지 않음getline()
에서 최대 허용 문자 수를 읽고난 뒤 다음 문자가 개행문자가 아닌 경우failbit
를 설정- 반면
get()
은 최대 허용 문자 수를 읽더라도failbit
를 설정하지 않음(단peek()
을 사용하여 다음 입력 문자를 확인하는 것으로 대체할 수 있음)
그 밖의 istream 메소드
istream
에는 다양한 메소드들이 존재함
read()
: 주어진 수의 바이트들을 읽어서 지정된 위치에 저장- 입력에 널문자를 덧붙이지 않으며, 문자열 형태로 변환하지 않음
- 리턴형이
istream &
이기 때문에 연이어 사용할 수 있음
peek()
: 입력 스트림으로부터 추출하지 않고 다음 문자를 리턴하기만 함gcount()
: 형식이 설정되지 않은 마지막 추출 메소드(>>
외의 다른 메소드들)가 읽은 문자 수를 리턴putback()
: 어떤 문자를 입력 스트림에 삽입하며,istream &
형을 리턴하기 때문에 이어서 처리할 수 있음
// peeker.cpp
#include <iostream>
int main()
{
using std::cout;
using std::cin;
using std::endl;
char ch;
while (cin.get(ch))
{
if (ch != '#')
cout << ch;
else
{
cin.putback(ch);
break;
}
}
if (!cin.eof())
{
cin.get(ch);
cout << endl << ch << "은 다음 입력 문자입니다.\n";
}
else
{
cout << "파일 끝에 도달했습니다.\n";
std::exit(0);
}
while (cin.peek() != '#')
{
cin.get(ch);
cout << ch;
}
if (!cin.eof())
{
cin.get(ch);
cout << endl << ch << "은 다음 입력 문자입니다.\n";
}
else
cout << "파일 끝에 도달했습니다.\n";
return 0;
}
// truncate.cpp
#include <iostream>
const int SLEN = 10;
inline void eatline() { while (std::cin.get() != '\n') continue; }
int main()
{
using std::cout;
using std::cin;
using std::endl;
char name[SLEN];
char title[SLEN];
cout << "이름을 입력하십시오 : ";
cin.get(name, SLEN);
if (cin.peek() != '\n')
cout << "죄송합니다. 이름란이 좁아서 " << name
<< "만 적어 넣었습니다." << endl;
eatline();
cout << name << " 씨! 직위를 입력하십시오 : \n";
cin.get(title, SLEN);
if (cin.peek() != '\n')
cout << "직위도 뒷부분을 잘랐습니다.\n";
eatline();
cout << "이름 : " << name
<< "\n직위 : " << title << endl;
return 0;
}
17.4 파일 입력과 출력
C++의 입출력 클래스 패키지는 파일 입출력을 표준 입출력처럼 다룸
- 파일에 기록시
ofstream
객체 생성 후 삽입 연산자<<
또는write()
와 같은ostream
메소드를 사용 - 파일로부터 읽을시
ifstream
객체 생성 후 추출 연산자>>
또는get()
과 같은istream
메소드를 사용 - 이 때 새롭게 열리는 파일을 입력 스트림과 연결시켜야하며, 이러한 작업을 돕는 클래스들이
fstream
헤더 파일에 정의되어있음
간단한 파일 입출력
프로그램이 파일 기록시의 절차는 다음과 같음
- 출력 스트림을 관리하기 위해
ofstream
객체 생성 open()
메소드를 사용하여 객체를 특정한 파일에 연결시킴cout
을 사용하는 것과 동일한 방법으로 객체를 사용함- 이 때
ofstream
클래스는 버퍼를 경유하는 출력을 사용하여 데이터 전송 속도를 향상시킴
파일을 읽을 때의 절차는 다음과 같음
- 입력 스트림을 관리하기 위해
ifstream
객체 생성 open()
또는ifstream
객체의 생성자를 사용하여 객체를 특정한 파일에 연결시킴cin
을 사용하는 것과 동일한 방법으로 객체를 사용함- 이 때
ifstream
클래스 역시 버퍼를 사용함
입력 스트림 혹은 출력 스트림 객체의 수명이 다했을시 파일과의 연결은 자동으로 닫힘
또는 close()
메소드를 사용해 명시적으로 파일과의 연결을 끊을 수도 있음
단, 이 때 스트림 자체는 여전히 유지됨
// fileio.cpp
#include <iostream>
#include <fstream>
#include <string>
int main()
{
using namespace std;
string filename;
cout << "새 파일을 위한 이름을 입력하십시오 : ";
cin >> filename;
ofstream fout(filename.c_str());
fout << "비밀 번호 노출에 주의하십시오.\n";
cout << "비밀 번호를 입력하십시오 : ";
float secret;
cin >> secret;
fout << "귀하의 비밀 번호는 " << secret << "입니다.\n";
fout.close();
ifstream fin(filename.c_str());
cout << filename << " 파일의 내용은 다음과 같습니다 : \n";
char ch;
while (fin.get(ch))
cout << ch;
cout << "프로그램을 종료합니다.\n";
fin.close();
return 0;
}
스트림 검사와 is_open()
C++의 파일 스트림 클래스들은 ios_base
클래스로부터 하나의 스트림 상태 멤버를 상속받음
스트림에 이상이 없을시 상태는 0이며, 문제가 발생시 특정 비트가 1로 설정됨
따라서 사용자는 가장 최근의 스트림 오퍼레이션의 성공 여부를 알기 위해 스트림 상태를 검사할 수 있음
여러 개의 파일 열기
하나의 프로그램이 파일 여러개를 동시에 열 경우 각 파일마다 서로 다른 스트림을 생성해야함
반면 파일들을 차례로 처리해야 하는 경우, 하나의 스트림을 열어 각 파일에 차례로 연결시킴
명령행 처리
파일 처리 프로그램들은 일반적으로 명령행 매개변수를 사용하여 파일들을 식별함
- 명령행 매개변수 : 명령을 입력하는 명령행에 나타나는 매개변수
int main(int argc, char *argv[])
형태의 원형을 가진main()
함수를 사용하여 프로그램이 명령행 매개변수에 접근할 수 있음argc
: 명령행 매개변수들의 수, 명령어 자체도 개수에 포함argv
:char
포인터를 지시하는 포인터, 즉 명령행에 있는 문자열들의 배열
// count.cpp
#include <iostream>
#include <fstream>
#include <cstdlib>
int main(int argc, char* argv[])
{
using namespace std;
if (argc == 1)
{
cerr << "사용법 : " << argv[0] << " filename[s]\n";
exit(EXIT_FAILURE);
}
ifstream fin;
long count;
long total = 0;
char ch;
for (int file = 1; file < argc; file++)
{
fin.open(argv[file]);
if (!fin.is_open())
{
cerr << argv[file] << " 파일을 열 수 없습니다.\n";
fin.clear();
continue;
}
count = 0;
while (fin.get(ch))
count++;
cout << argv[file] << " 파일에 들어있는 문자 수는 " << count << "입니다.\n";
total += count;
fin.clear();
fin.close();
}
cout << "전체 파일에 들어있는 문자 수는 " << total << "입니다.\n";
return 0;
}
파일 모드
파일 모드는 파일이 사용되는 방법을 나타냄
파일 이름으로 파일 스트림 객체를 초기화하거나 open()
메소드를 사용하여 스트림을 파일에 연결할 때 파일 모드를 지정하는 두번째 매개변수를 사용할 수 있음
ifstream fin("banjo", model);
과 같은 형태- 또는
ofstream fout; fout.open("harp", mode2);
와 같은 형태
ios_base
클래스에 모드를 나타내는 openmode
형이 정의되어있으며, fmtflags
나 iostate
형과 같은 비트마스크형임
in
: 파일을 읽기 위해 염out
: 파일에 쓰기 위해 염ate
: 파일을 열 때 파일 끝을 찾음app
: 파일 끝에 덧붙임trunc
: 파일이 이미 존재하면 파일 내용을 지움binary
: 2진 파일
파일 모드 지정 매개변수는 각 메소드마다 설정된 디폴트값이 있음
ifstream
의open()
메소드 및 생성자는in
을 디폴트로 사용ofstream
의open()
메소드 및 생성자는out | trunc
를 디폴트로 사용fstream
클래스는 디폴트를 지원하지 않기 때문에 명시적으로 지정해주어야 함
C++의 모드와 C의 모드의 대응 관계는 다음과 같음
in
-r
: 읽기 위해 염out
-w
:out | trunc
와 같음out | trunc
-w
: 쓰기 위해 열고, 파일이 존재할시 내용을 비움out | app
-a
: 쓰기 위해 열고 뒤에 덧붙임in | out
-r+
: 읽기/쓰기 겸용, 파일 안의 어디에나 쓸 수 있음in | out | trunc
-w+
: 읽기/쓰기 겸용, 파일이 존재할시 먼저 내용을 비움c++mode | binary
-cmodeb
:c++mode
또는 상응하는cmode
및 2진 모드로 염c++mode | ate
-cmode
: 지신된 모드로 열고 파일의 끝으로 파일 포인터를 이동시키며, C에서는 별도의 함수 호출을 사용함
파일에 덧붙이기
// append.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
const char * file = "guests.txt";
int main()
{
using namespace std;
char ch;
ifstream fin;
fin.open(file);
if (fin.is_open())
{
cout << file << " 파일의 현재 내용은 다음과 같습니다 : \n";
while (fin.get(ch))
cout << ch;
fin.close();
}
ofstream fout(file, ios_base::out | ios_base::app);
if (!fout.is_open())
{
cerr << "출력을 위해 " << file << " 파일을 열 수 없습니다.\n";
exit(EXIT_FAILURE);
}
cout << "새로운 손님 이름들을 입력하십시오(끝내려면 빈 줄 입력) : \n";
string name;
while (getline(cin, name) && name.size() > 0)
{
fout << name << endl;
}
fout.close();
fin.clear();
fin.open(file);
if (fin.is_open())
{
cout << file << " 파일의 개정된 내용은 다음과 같습니다 : \n";
while (fin.get(ch))
cout << ch;
fin.close();
}
cout << "프로그램을 종료합니다.\n";
return 0;
}
2진 파일
파일에 데이터 저장시 데이터를 텍스트 형식 또는 2진 형식으로 저장할 수 있음
2진 형식으로 저장시 컴퓨터의 내부적인 표현 그대로, 일반적으로는 64비트의 double
표현으로 저장함
- 텍스트 형식은 읽기가 쉬우며, 한 컴퓨터에서 다른 컴퓨터 시스템으로 쉽게 옮길 수 있음
- 2진 형식은 수의 경우 변환 에러나 반올림 에러 없이 더 정확하게 저장 가능하며, 처리 속도가 빠르고 공간을 덜 차지함
const int LIM = 20;
struct planet
{
char name[LIM];
double population;
double g;
};
planet pl;
ofstream fout("planets.dat", ios_base::out | ios_base::app);
fout << pl.name << " " << pl.population << " " << pl.g << "\n";
ofstream fout("planets.dat", ios_base::out | ios_base::app | ios_base::binary);
fout.write((char *) &pl, sizeof pl);
구조체를 텍스트 형식으로 저장시 가독성을 위해 공백을 넣고, 각 멤버를 명시적으로 지정하는 등의 작업이 수행됨
구조체를 2진 형식으로 저장시 구조체 전체를 하나의 단위로 저장하여 텍스트를 읽을 수는 없지만 정보가 더 정확하게 저장되며 코드 작성도 편리해짐
- 이 때
ios_base::binary
상수를 사용하여 2진 파일 형식을 지정해주어야함 write()
멤버 함수를 사용하여 메모리에서 파일로 지정한 수만큼 바이트들을 복사함- 변수의 주소를
char *
형으로 변환해주어야함 - 가상 함수를 사용하지 않는 클래스들과 함께 사용할 수 있음
// binary.cpp
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
inline void eatline() { while (std::cin.get() != '\n') continue; }
struct planet
{
char name[20];
double population;
double g;
};
const char * file = "planets.dat";
int main()
{
using namespace std;
planet pl;
cout << fixed << right;
ifstream fin;
fin.open(file, ios_base::in | ios_base::binary);
if (fin.is_open())
{
cout << file << " 파일의 현재 내용은 다음과 같습니다 : \n";
while (fin.read((char *) &pl, sizeof pl))
{
cout << setw(20) << pl.name << " : "
<< setprecision(0) << setw(12) << pl.population
<< setprecision(2) << setw(6) << pl.g << endl;
}
fin.close();
}
ofstream fout(file, ios_base::out | ios_base::app | ios_base::binary);
if (!fout.is_open())
{
cerr << "출력을 위해 " << file << " 파일을 열 수 없습니다. \n";
exit(EXIT_FAILURE);
}
cout << "행성의 이름을 입력하십시오(끝내려면 빈 줄 입력) : \n";
cin.get(pl.name, 20);
while (pl.name[0] != '\0')
{
eatline();
cout << "행성의 인구를 입력하십시오 : ";
cin >> pl.population;
cout << "행성의 중력가속도를 입력하십시오 : ";
cin >> pl.g;
eatline();
fout.write((char *) &pl, sizeof pl);
cout << "행성의 이름을 입력하십시오(끝내려면 빈 줄 입력) : \n";
cin.get(pl.name, 20);
}
fout.close();
fin.clear();
fin.open(file, ios_base::in | ios_base::binary);
if (fin.is_open())
{
cout << file << " 파일의 개정된 내용은 다음과 같습니다 : \n";
while (fin.read((char *) &pl, sizeof pl))
{
cout << setw(20) << pl.name << " : "
<< setprecision(0) << setw(12) << pl.population
<< setprecision(2) << setw(6) << pl.g << endl;
}
fin.close();
}
cout << "프로그램을 종료합니다.\n";
return 0;
}
구조체 멤버에 문자 배열 대신 string
객체가 사용될 경우, string
객체는 자체적으로 문자열을 포함하지 않고 대신 문자열이 저장되어있는 메모리 위치를 가리키는 포인터를 포함하기 때문에 구조체 복사시 주소만 복사됨
따라서 프로그램이 다시 실행될 때 해당 주소가 의미가 없어지기 때문에 원하는 결과를 얻을 수 없음
임의 접근
임의 접근 : 파일의 특정 위치에 순차적으로 접근하는 것이 아닌 직접 그 위치로 이동
파일이 같은 크기의 레코드(서로 관련이 있는 데이터들의 한 집합)들로 이루어진 집합일 경우 가장 간단하게 적용됨
seekg()
: 입력 포인터를 주어진 위치로 옮김 seekp()
: 출력 포인터를 주어진 위치로 옮김
- 실제 파일에 있는 위치가 아닌 버퍼에 있는 위치를 지시함
istream & seekg(streamoff, ios_base::seekdir);
형태의 원형을 사용시 두번째 매개변수로 지정된 파일 위치에서 몇 바이트 떨어져있는지를 계산하여 파일 위치를 찾음ios_base::beg
: 시작 위치로부터의 오프셋 측정ios_base::cur
: 현재 위치로부터의 오프셋 측정ios_base::end
: 끝 위치로부터의 오프셋을 측정
istream & seekg(streampos);
형태의 원형을 사용시 파일의 시작 위치로부터 몇 바이트 떨어져있는지를 계산하여 위치를 찾음- 파일 포인터의 현재 위치는 입력 스트림의 경우
tellg()
, 출력 스트림의 경우tellp()
메소드를 사용하여 확인할 수 있음
// random.cpp
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
inline void eatline() { while (std::cin.get() != '\n') continue; }
const int LIM = 20;
struct planet
{
char name[20];
double population;
double g;
};
const char * file = "planets.dat";
int main()
{
using namespace std;
planet pl;
cout << fixed << right;
fstream finout;
finout.open(file, ios_base::in | ios_base::out | ios_base::binary);
int ct = 0;
if (finout.is_open())
{
finout.seekg(0);
cout << file << " 파일의 현재 내용은 다음과 같습니다 : \n";
while (finout.read((char *) &pl, sizeof pl))
{
cout << ct++ << " : " << setw(LIM) << pl.name << " : "
<< setprecision(0) << setw(12) << pl.population
<< setprecision(2) << setw(6) << pl.g << endl;
}
if (finout.eof())
finout.clear();
else
{
cerr << file << " 파일을 읽다가 에러 발생.\n";
exit(EXIT_FAILURE);
}
}
else
{
cerr << file << " 파일을 열 수 없습니다. 종료합니다.\n";
exit(EXIT_FAILURE);
}
cout << "수정할 레코드 번호를 입력하십시오 : ";
long rec;
cin >> rec;
eatline();
if (rec < 0 || rec >= ct)
{
cerr << "잘못된 레코드 번호입니다. 종료합니다.\n";
exit(EXIT_FAILURE);
}
streampos place = rec * sizeof pl;
finout.seekg(place);
if (finout.fail())
{
cerr << "레코드를 찾다가 에러 발생\n";
exit(EXIT_FAILURE);
}
finout.read((char *) &pl, sizeof pl);
cout << file << " 현재 레코드의 내용 : \n";
cout << rec << " : " << setw(LIM) << pl.name << " : "
<< setprecision(0) << setw(12) << pl.population
<< setprecision(2) << setw(6) << pl.g << endl;
if (finout.eof())
finout.clear();
cout << "행성의 이름을 입력하십시오 : ";
cin.get(pl.name, LIM);
eatline();
cout << "행성의 인구를 입력하십시오 : ";
cin>> pl.population;
cout << "행성의 중력가속도를 입력하십시오 : ";
cin >> pl.g;
finout.seekp(place);
finout.write((char *) &pl, sizeof pl) << flush;
if (finout.fail())
{
cerr << "쓰다가 에러 발생.\n";
exit(EXIT_FAILURE);
}
ct = 0;
finout.seekg(0);
cout << file << " 파일의 개정된 내용은 다음과 같습니다 : \n";
while (finout.read((char *) &pl, sizeof pl))
{
cout << ct++ << " : " << setw(LIM) << pl.name << " : "
<< setprecision(0) << setw(12) << pl.population
<< setprecision(2) << setw(6) << pl.g << endl;
}
finout.close();
cout << "프로그램을 종료합니다.\n";
return 0;
}
C++에서 임시 파일들의 이름은 tmpnam()
함수에 의해 생성됨
char* tmpnam(char* pszName)
형태의 원형을 가짐- 생성된 이름은
pszName
이 지시하는 C스타일의 문자열에 저장됨 cstdio
에 정의되어있는L_tmpnam
은 파일 이름의 문자 수,TMP_MAX
상수는 현재 디렉토리에 중복된 파일 이름을 생성하지 않고tmpnam()
이 호출될 수 있는 최대 허용 횟수를 제한함- 즉,
tmpnam()
을 사용함으로써 이름당L_tmpnam
개까지 문자를 가질 수 있는TMP_NAM
개의 고유한 파일 이름들을 생성할 수 있음
17.5 인코어 형식의 지정
iostream
계열은 프로그램과 단말기 사이의 입출력을 지원 fstream
계열은 동일한 인터페이스로 프로그램과 파일 사이의 입출력을 지원 sstream
계열은 동일한 인터페이스로 프로그램과 string
객체 사이의 입출력을 제공
- 인코어 형식 지정 :
string
객체로부터 형식이 지정된 정보를 읽거나,string
객체에 형식이 지정된 정보를 기록하는 과정 sstream
헤더 파일은ostream
클래스에서 파생된ostringstream
클래스를 정의하며,ostringstream
객체는cout
과 함께 사용할 수 있는 메소드들을 사용할 수 있음
// strout.cpp
#include <iostream>
#include <sstream>
#include <string>
int main()
{
using namespace std;
ostringstream outstr;
string hdisk;
cout << "하드디스크의 모델명이 무엇입니까? ";
getline(cin, hdisk);
int cap;
cout << "하드디스크의 용량이 몇 GB입니까? ";
cin >> cap;
outstr << hdisk << " 하드디스크의 용량은 "
<< cap << " GB입니다.\n";
string result = outstr.str();
cout << result;
return 0;
}
ostringstream
클래스의 str()
멤버 함수는 버퍼의 내용으로 초기화된 string
객체를 리턴하며,해당 객체를 동결시켜 더이상 정보를 써 넣을 수 없게 만듬
// strin.cpp
#include <iostream>
#include <sstream>
#include <string>
int main()
{
using namespace std;
string lit = "길섶 민들레 꽃씨대롱 방울로 부풀어 "
"여윈 목 아프게 빼어 들고 "
"아기씨 실어 나를 바람 기다리누나.";
istringstream instr(lit);
string word;
while (instr >> word)
cout << word << endl;
return 0;
}
istringstream
클래스는 istream
메소드 계열을 사용하여 istringstream
객체로부터 데이터를 읽을 수 있게 해줌
연습문제
- 입력과 출력을 관리하는 클래스, 상수, 조정자들을 정의
모든 프로그램에 연결되는 표준 입력 스트림과 출력 스트림들을 위해 사용되는 표준 객체들을 생성함
객체들은 입출력에 사용되는 스트림과 버퍼를 관리 - 키보드 입력은 문자를 발생시키기 때문에 연속된 문자들을 묶어 하나의 숫자인 121으로 변환시켜주어야함
- 출력을 파일로 리디렉션할시 표준 출력은 화면이 아니라 파일에 연결되지만 표준 에러는 계속해서 화면으로 연결됨
- 각 기본 데이터형에 대해 오버로딩된
<<
연산자를 이용함 - 메소드를 호출한 객체의 참조형을 리턴하는 출력 메소드들은 연이어서 출력을 할 수 있음
-
int main() { using namespace std; cout << "숫자 하나를 입력하세요 : "; int i; cin >> i; cout << i << endl << oct << i << endl << hex << i << endl; return 0; }
-
#include <iostream> #include <iomanip> #include <string> int main() { using namespace std; cout << "이름을 입력하십시오 : "; string name; getline(cin, name); cout << "시간당 급료를 입력하십시오 : "; double pay; cin >> pay; cout << "근로 시간을 입력하십시오 : "; double time; cin >> time; cout << "첫째 형식 : \n"; cout << showpoint << fixed << right; cout << setw(30) << name << ": $ " << setprecision(2) << setw(10) << pay << ":" << setprecision(1) << setw(5) << time << "\n"; cout << left; cout << "둘째 형식 : \n"; cout << setw(30) << name << ": $ " << setprecision(2) << setw(10) << pay << ":" << setprecision(1) << setw(5) << time << "\n"; return 0; }
cin >>
은 화이트스페이스를 제외하고 받으므로ct1 = 5;
를 출력함cin.get()
은 화이트스페이스를 포함하므로ct2 = 9
를 출력함while (cin.get() != '\n') continue;
의 경우 행의 끝(개행 문자가 나오기 전)까지 완전하게 읽고 버림
반면cin.ignore(80, '\n');
의 경우 입력받은 문자가 최대 허용 문자 수를 초과할시 바르게 동작하지 않으며, 처음 80개 문자를 건너뛰기만 함
'개인공부 > C++ 기초플러스' 카테고리의 다른 글
C++ Primer 17 Exercise (0) | 2023.02.21 |
---|---|
C++ Primer 16 Exercise (0) | 2023.02.21 |
C++ Primer 16 (0) | 2023.02.21 |
C++ Primer 15 Exercise (0) | 2023.02.21 |
C++ Primer 15 (0) | 2023.02.21 |
댓글