따라하며 배우는 C++ 18. 입력과 출력
18.1 istream으로 입력받기
#include <iostream>
#include <string>
#include <iomanip> //input / output manipulators
using namespace std;
int main()
{
//기본적으로 stream은 버퍼에 저장되어 있는 걸
//임시적으로 일부씩 꺼내오는 것
char buf[10];
cin >> setw(10) >> buf; //최대 10글자까지만 버퍼에서 받을 수 있도록 방지함
//여기서 null 캐릭터 자리는 비워둬서 실질적으론 9글자까지만 가능함.
cout << buf << endl;
cin >> setw(10) >> buf;
cout << buf << endl;
cin >> setw(10) >> buf;
cout << buf << endl;
//아무것도 없을 때까지 버퍼에서 순차적으로 가져올 수 있다.
return 0;
}
#include <iostream>
#include <string>
#include <iomanip> //input / output manipulators
using namespace std;
int main()
{
char ch;
while (cin >> ch)
cout << ch;
return 0;
}
위에서처럼 계속 입력받을 수 있다.
그러나 space가 사라진다.
원래는 빈 칸으로 입력자들의 구분을 해 줘서, 사라지는 것.
ex.
int i;
float f;
cin >> i >> f;
cout << i << " " << f << endl;
#include <iostream>
#include <string>
#include <iomanip> //input / output manipulators
using namespace std;
int main()
{
char ch;
while (cin.get(ch))
cout << ch;
return 0;
}
get으로 space도 받아올 수 있음.
이 때 char buf[5]; cin.get(buf,5);로 이용하면 최대 5글자씩 버퍼에서 받아옴.
cin.gcount(); //버퍼에서 몇 글자 읽어들였는지 숫자를 세어 주는 함수.
cin.getline(); //line 한 줄을 다 읽어들인다. (사이즈가 제한되어 있으면 그 사이즈만큼만 읽어오나,
//한 줄을 다 읽어들이기 때문에 버퍼가 비게 될 수도 있다.
#include <iostream>
#include <string>
#include <iomanip> //input / output manipulators
using namespace std;
int main()
{
char buf[100];
cin.get(buf, 100);
cout << cin.gcount() << " " << buf << endl;
cin.getline(buf, 100);
cout << cin.gcount() << " " << buf << endl;
}
getline은 줄바꿈 문자까지 읽어들인다.
#include <iostream>
#include <string>
#include <iomanip> //input / output manipulators
using namespace std;
int main()
{
string buf;
getline(cin, buf);
cout << cin.gcount() << " " << buf << endl;
}
사이즈를 고려할 필요 없어서 편하다.
#include <iostream>
#include <string>
#include <iomanip> //input / output manipulators
using namespace std;
int main()
{
char buf[1024];
cin.ignore();
cin >> buf;
cout << buf << endl;
//읽을 때 한 글자를 무시함.
//인수가 생략되면 1글자, 넣으면 n글자.
cin >> buf;
//cout << (char)cin.peek() << endl;
cout << buf << endl;
}
//peek은 한 글자를 들여닫보기만 하고, 실제로 꺼내진 않는다.
#include <iostream>
#include <string>
#include <iomanip> //input / output manipulators
using namespace std;
int main()
{
char buf[1024];
cin >> buf;
cout << buf << endl;
cin.unget();
cin >> buf;
cout << buf << endl;
}
unget은 마지막으로 가져온 글자를 버퍼에 도로 넣는다.
putback은 정해진 문자를 버퍼에 넣는다(cin.putback('A';)처럼)
18.2 ostream으로 출력하기
#include <iostream>
#include <string>
#include <iomanip> //input / output manipulators
using namespace std;
int main()
{
cout.setf(std::ios::showpos);
cout << 108 << endl;
// +기호를 붙일 수 있다.
cout.unsetf(std::ios::showpos);
cout << 109 << endl;
//지정했던 플래그를 해제한다.
cout.unsetf(std::ios::dec);
cout.setf(std::ios::hex); //10진수 플래그를 꺼주고 16진수 설정을 넣어야 함
//cout.setf(std::ios::hex, std::ios::basefield);
// cout<<std::hex; 도 가능.
//이렇게 하면 한번에 가능.
cout << 108 << endl;
cout.setf(std::ios::uppercase); //대문자
cout << 108 << endl;
cout << std::dec; //다시 10진수로.
cout << 108 << endl;
cout << std::boolalpha;
cout << true << " " << false << endl;
cout << std::defaultfloat;
cout << std::setprecision(3) << 123.456 << endl;
cout << std::setprecision(4) << 123.456 << endl;
cout << std::setprecision(5) << 123.456 << endl;
cout << std::fixed;
cout << std::setprecision(3) << 123.456 << endl;
cout << std::setprecision(4) << 123.456 << endl;
cout << std::setprecision(5) << 123.456 << endl;
cout << std::scientific;
cout << std::setprecision(3) << 123.456 << endl;
cout << std::setprecision(4) << 123.456 << endl;
cout << std::setprecision(5) << 123.456 << endl;
cout << std::showpoint; //소수점 보이게
cout << std::setprecision(3) << 123.456 << endl;
cout << std::setprecision(4) << 123.456 << endl;
cout << std::setprecision(5) << 123.456 << endl;
cout << -12345 << endl;
cout << std::setw(10) << -12345 << endl; //10글자 자리를 채워라
cout << std::setw(10) << std::left << -12345 << endl;
cout << std::setw(10) << std::right << -12345 << endl;
cout << std::setw(10) << std::internal << -12345 << endl;
cout.fill('*');
cout << std::setw(10) << -12345 << endl; //10글자 자리를 채워라
cout << std::setw(10) << std::left << -12345 << endl;
cout << std::setw(10) << std::right << -12345 << endl;
cout << std::setw(10) << std::internal << -12345 << endl;
}
18.3 문자열 스트림
지금까지 살펴본 입출력 stream은 console에 대한 작용을 했다면,
문자열 stream은 문자열 흐름의 버퍼 역할을 한다.
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream os;
os << "Hello, World!"; //insertion operator
os.str("Hello, World!");
string str;
os >> str;
cout << str << endl; // >> : extraction operator
string str2;
str2 = os.str();
cout << str2 << endl;
}
여기서 os.str()을 하면 이전의 내용은 사라지고 새 내용으로 덮어씌워진다.
os<<"Hello, World!"<<endl ; 이라고 하면 줄바꿈 문자도 스트림에 포함된다.
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream os;
os << "12345 67.89";
string str1;
string str2;
os >> str1 >> str2;
cout << str1 << "|" << str2 << endl;
int i = 12345;
double d = 67.89;
os << i << " " << d;
os >> str1 >> str2;
cout << str1 << "|" << str2 << endl;
}
space로 분리해서 집어넣을 수 있다.
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream os;
os.str(""); //stream 초기화
cout << os.str() << endl; //함수 오버로딩
//이 경우 return함.
//os.str(""); os.str(string());
//버퍼를 지워줄 수 있음.
//or.str(""); 은 state까지만 지워줌(??)
}
18.4 흐름 상태stream states와 입력 유효성 검증input validation
#include <iostream>
#include <cctype>
#include <string>
#include <bitset>
using namespace std;
void printCharacterClassification(const int& i)
{
}
void printStates(const std::ios& stream)
//filestream, i/ostream 모두 공통적으로 사용할 수 있다.
//C언어의 printf보다 stream(cout)이 더 길게 느껴질 수도 있으나
//C언어에선 fprint라는 별도의 파일 입출력 함수를 써야 하는 데 반해
//C++에선 stream을 이용해 파일 입출력에도 console 입출력에서 사용하던 그대로
//입출력을 행할 수 있다.
{
cout << boolalpha;
cout << "good() = " << stream.good() << endl; //상태가 좋은가
cout << "eof()=" << stream.eof() << endl; //end of file인가
cout << "fial()=" << stream.fail() << endl; //good의 반대.
cout << "bad()=" << stream.bad() << endl; //상태가 좋지 않은가.
}
bool isAllDigit(const string& str)
{
return true;
}
int main()
{
while (true)
{
int i;
cin >> i;
printStates(cin);
cout << boolalpha;
//printStates처럼 flag자체를 false, true로 검증해 확인하는 방법이 있고
//비트 마스크로 확인하는 방법이 있다.
cout << std::bitset<8>(cin.rdstate()) << endl;
cout << std::bitset<8>(std::istream::goodbit) << endl;
cout << std::bitset<8>(std::istream::failbit) << endl;
cout << !bool((cin.rdstate() & std::istream::failbit) != 0) << endl;
//good bit가 모두 0이라서 추출이 되지 않으므로 failtbit로 돌려서 추출함
//cin.rdstate() == stad::istream::goodbit; 로 해도 됨
//printCharacterClassfication(i);
cin.clear();
cin.ignore(1024, '\n');
}
}
정수 넣을 자리에 문자를 넣으면 문제가 발생하고,
실수를 넣으면 절삭될 수 있다.
#include <iostream>
#include <cctype>
#include <string>
#include <bitset>
using namespace std;
void printCharacterClassification(const int& i)
{
//cctype에 들어있는 함수들
cout << boolalpha;
//여기선 bool이 아닌 integer로 return함.
//
cout << "isalnum " << bool(std::isalnum(i)) << endl;
cout << "isblank " << bool(std::isblank(i)) << endl;
cout << "isdigit " << bool(std::isdigit(i)) << endl;
cout << "islower " << bool(std::islower(i)) << endl;
cout << "Isupper " << bool(std::isupper(i)) << endl;
}
void printStates(const std::ios& stream)
//filestream, i/ostream 모두 공통적으로 사용할 수 있다.
//C언어의 printf보다 stream(cout)이 더 길게 느껴질 수도 있으나
//C언어에선 fprint라는 별도의 파일 입출력 함수를 써야 하는 데 반해
//C++에선 stream을 이용해 파일 입출력에도 console 입출력에서 사용하던 그대로
//입출력을 행할 수 있다.
{
cout << boolalpha;
cout << "good() = " << stream.good() << endl; //상태가 좋은가
cout << "eof()=" << stream.eof() << endl; //end of file인가
cout << "fial()=" << stream.fail() << endl; //good의 반대.
cout << "bad()=" << stream.bad() << endl; //상태가 좋지 않은가.
}
bool isAllDigit(const string& str)
{
return true;
}
int main()
{
while (true)
{
char i;
cin >> i;
printStates(cin);
printCharacterClassification(i);
cin.clear();
cin.ignore(1024, '\n');
}
}
#include <iostream>
#include <cctype>
#include <string>
#include <bitset>
using namespace std;
bool isAllDigit(const string& str)
{
bool ok_flag = true;
for(auto e:str)
if (!std::isdigit(e))
{
ok_flag = false;
break;
}
return ok_flag;
}
int main()
{
cout << boolalpha;
cout << isAllDigit("1234") << endl;
cout << isAllDigit("a1234") << endl;
}
isblack는 위처럼 문자열 안에서 한 문자씩 비교할 때 쓰인다!
18.5 정규 표현식regular expressions 소개
#include <iostream>
#include <regex> //c++ 11부터 들어옴.
using namespace std;
int main()
{
regex re("\\d"); //\d는 숫자가 하나인지 아닌지 판별함.
//앞에 있는 \는 \를 문자로 쓰기 위한 것
//d+이면 한 개 이상의 숫자
//d*이면 0개 이상의 숫자
//regex re("[[:digit:]]{3}");
//digit을 3개를 딱 맞춰 받겠다. \d와 [[:digit:]]과 같다.
//regex re("[A-Z]+");
//대문자 A~Z까지의 문자를 한 개 이상 받겠다.
//{1, 5}를 하면 최소 1개, 5개 이하.
//regex re("[A-Z]{3}");
//regex re("([0-9]{1})([-]?)([0-9]{1,4})");
//0~9까지 숫자 중 하나, 뒤에는 -가 있어도 되고, 없어도 되고.
string str;
while (true)
{
getline(cin, str);
if (std::regex_match(str, re)) //정규표현식과 맞는지 비교함
cout << "Match" << endl;
else
cout << "No match" << endl;
//print matches,, 매치되는 부분만 프린트.
{
auto begin = std::sregex_iterator(str.begin(), str.end(), re);
auto end = std::sregex_iterator();
for (auto itr = begin; itr != end; ++itr)
{
std::smatch match = *itr;
cout << match.str() << " ";
}
cout << endl;
}
cout << endl;
}
}
18.6 기본적인 파일 입출력
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib> //exit()
#include <sstream>
using namespace std;
int main()
{
//writing
if (true)
{
ofstream ofs("my_fisrt_file.dat"); //ios::app, ios::binary
//ofs.open("my_first_file.dat");
if (!ofs)
{
cerr << "Couldn't open file " << endl;
exit(1);
}
ofs << "Line 1" << endl;
ofs << "Line 2" << endl;
//ofs는 아스키 코드로 출력을 한다. 메모장으로 열기 가능.
/*
const unsigned num_data = 10;
ofs.write((char*) &
for (int i = 0; i < num_data; ++i)
ofs.write((char*)&i, sizeof(i));
ss << "Line 1" << endl;
ss << "Line 2" << endl;
string str = ss.str();
unsigned str_length = str.size();
ofs.write((char*)&str_length, sizeof(str_length));
ofs.write(str.c_str(), str_length);
ofs.close();
*/
}
//reading
if (true)
{
ifstream ifs("my_first_file.dat");
if (!ifs)
{
cerr << "Cannot open file" << endl;
exit(1);
}
while (ifs)
{
std::string str;
getline(ifs, str);
std::cout << str << endl;
}
}
}
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib> //exit()
#include <sstream>
using namespace std;
int main()
{
//writing
if (true)
{
ofstream ofs("my_fisrt_file.dat"); //ios::app, ios::binary
//ofs.open("my_first_file.dat");
if (!ofs)
{
cerr << "Couldn't open file " << endl;
exit(1);
}
const unsigned num_data = 10;
ofs.write((char*)&num_data, sizeof(num_data));
for (int i = 0; i < num_data; ++i)
ofs.write((char*)&i, sizeof(i));
//위는 바이너리로 저장하는 방법
//아스키 코드로 저장하면 프로그램이 느려진다.
/*
ss << "Line 1" << endl;
ss << "Line 2" << endl;
string str = ss.str();
unsigned str_length = str.size();
ofs.write((char*)&str_length, sizeof(str_length));
ofs.write(str.c_str(), str_length);
*/
//ofs.close(); //not necessary
}
//reading
if (true)
{
ifstream ifs("my_first_file.dat");
if (!ifs)
{
cerr << "Cannot open file" << endl;
exit(1);
}
unsigned num_data = 0;
ifs.read((char*)&num_data, sizeof(num_data));
//바이너리 파일은 꼭 파일의 크기를 먼저 인지해야 한다.
for (unsigned i = 0; i < num_data; ++i)
{
int num;
ifs.read((char*)&num, sizeof(num));
cout << num << endl;
}
}
}
if (true)
{
ofstream ofs("my_first_file.dat", ios::app);
if (!ofs)
{
cerr << "Couldn't open file" << endl;
exit(1);
}
ofs << "Line 1" << endl;
ofs << "Line 2" << endl;
}
파일쓰기를 append모드(app)로 하면 이미 있는 파일을 초기화해서 쓰지 않고,
뒤에 덧붙여 쓴다.
//출력할 데이터를 문자열 하나에 쫙 담는 경우도 있다.
ss << "Line 1" <<endl;
ss << "Line 2" << endl;
string str = ss.str();
unsigned str_length = str.size();
ofs.write((char*)&str_length, sizeof(str_length));
ofs.write(str.c_str(), str_length);
//파일 쓰기
//파일 읽기
unsigned str_len = 0;
ifs.read((char*)&str_len, sizeof(str_len));
string str;
str.resize(str_len);
ifs.read(&str[0], str_len);
cout<<str<<endl;
18.7 파일의 임의 위치 접근하기
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib> //exit()
#include <sstream>
using namespace std;
int main()
{
const string filename = "my_file.txt";
//make a file
{
ofstream ofs(filename);
for (char i = 'a'; i <= 'z'; ++i)
ofs << i;
ofs << endl;
}
//read the file
{
ifstream ifs("my_file.txt");
ifs.seekg(5); //ifs.seekg(5, ios::beg);
cout << (char)ifs.get() << endl;
}
}
여기서 ifs.seekg(5)는 파일에서 다섯번째 글자를 읽는다.
다시 ifs.seekg(5, ios::cur)를 호출하면 현재 다섯번째 읽은 글자에서 다시 다섯 글자를 가서 그 문자를 읽어온다.
//ifs.seekg(0, ios::end);
파일 끝으로부터 맨 마지막 문자.
//ifs.tellg()
현재 위치를 알려줌.
ifs.seekg(-5, ios::end);
//파일 끝으로부터 5글자 앞.
string str;
getline(ifs, str);
//한 글자를 쫙 읽어옴
//fstream iofs(filename, ios::in | ios::out);
fstream iofs(filename);
iofs.seekg(5);
cout<< (char)iofs.get() << endl; //read
iofs.seekg(5);
iofs.put('A'); //write
위 예제는 파일 읽고, 쓰고를 한번에 하는 것.
seekg로 읽은 후 put을 하면 그 자리에 해당 문자가 덮어 씌워진다.
'개발 공부 > C++' 카테고리의 다른 글
따라하며 배우는 C++ 19. 모던 C++ 필수 요소들 (0) | 2020.07.04 |
---|---|
따라하며 배우는 C++ 17. string 문자열 클래스 (0) | 2020.07.03 |
따라하며 배우는 C++ 16. 표준 템플릿 라이브러리 (0) | 2020.07.03 |
따라하며 배우는 C++ 15. 의미론적 이동과 스마트 포인터 (0) | 2020.07.03 |
따라하며 배우는 C++ 14. 예외 처리 (0) | 2020.07.02 |