저자: Stephen Prata
🤔어렵지 않게 설명하는 것을 지향하는 책인데, 너무 많은 내용을 담으려다 산만해진 느낌이다.
참고) 책의 내용을 내가 필요한 내용 위주로 정리함.
역사를 좀 배워보자.
C++로 전환하려면 기존의 C 프로그래밍 습관을 과감히 버려야 한단다.. 🥴
✏️ C++ 변수 선언 스타일은 가능하면 그 변수를 처음 사용하는 가장 가까운 위치에 그 변수를 선언하는 것이다.
이 책을 읽으면서 이 분의 이야기가 간간이 언급될 것이다.

리누스 토발즈만큼이나 프로그래밍에 한 획을 그은 개발자 중에 한 분인 것 같다.
#include <iostream> // a PREPROCESSOR directive
// 전처리지시자
int main() // function header
{ // start of function body
using namespace std; // make definitions visible
cout << "Come up and C++ me some time."; // message
cout << endl; // 개행
cout << "You won't regret it!" << endl; // more output
return 0; // terminate main()
} // end of function body
#include <iostream> | 헤더파일의 종류 | 규칙 | 보기 | 설명 |
|---|---|---|---|
| C++ 구식 | .h 끝남 | iostream.h | C++ |
| C 구식 | .h 끝남 | math.h | C |
| C++ 최신 | 확장자 없음 | iostream | C++, namespace std |
| C 변환 스타일 | c접두어, 확장자 없음 | cmath |
이름 공간 지시자를 사용해야 한다.using namespace std; 만약 위가 없었다면, 아래와 같이 써야 했을 것이다. 이 때 사용하는 게 using 지시다. std::접두어 를 붙이지 않고도 std이름 공간에 정의되어 있는 이름들을 사용할 수 있다.#include <iostream> // a PREPROCESSOR directive
int main() // function header
{ // start of function body
using namespace std; // 게으른 방식, 모든 이름 사용 가능
std::cout << "Come up and C++ me some time."; // message
std::cout << std::endl; // start a new line
std::cout << "You won't regret it!" << endl; // more output
return 0; // terminate main()
} <<: 데이터를 출력 스트림에 집어넣는 삽입 연산자
cout: 문자열, 수, 문자 등을 포함한 여러가지 다양한 정보들을 출력하는 방법을 알고 있는 미리 정의된 객체.
조정자 endl
endl: cout은 문자열을 출력하고 나서 다음 행의 시작 위치로 커서를 자동으로 넘겨주지 않음. endl의 역할은 커서를 뒤로 넘겨준다. “\n”과도 비슷해보이는데, 이 책의 경우는 문자열을 출력할 때는 개행을 쓰고, 그 외의 것은 endl을 사용했다고 한다.
cin:
cin >> carrots; # 입력 스트림에서 문자를 가져옴
// scanf 였다면,
scanf("%d\n", &carrots);
[ C 언어 (Pointer 방식) ]
scanf <--- [ &carrots (주소값) ]
"내가 이 주소(번지수)를 알려줄 테니, 거기 가서 값을 직접 넣어!"
(위험성: 잘못된 주소를 넘기면 프로그램이 죽음)
[ C++ (Reference 방식) ]
cin >> <--- [ carrots (변수 자체) ]
"carrots라는 변수 자체를 너에게 빌려줄게(별명). 알아서 채워줘!"
(안정성: 실체가 있는 변수만 넘길 수 있어 훨씬 안전함)
개발자들이 주소를 직접 다루다가 실수하는 것을 방지하기 위해서 '참조자'라는 개념이 등장했다.
References were introduced primarily to support operator overloading.
(..)
References are not pointers; they are aliases for objects. ... The main use of references in C++ is to provide a way of passing arguments to functions that is as efficient as passing pointers but provides the notation of passing by value.
-- The Design and Evolution of C++
참조자를 좀 더 파보자
// C언어: 포인터 (우편함)
int* p = &a;
*p = 20; // "p라는 우편함에 적힌 주소로 가서(*), 그 집의 값을 바꿔라"
// C++: 참조자 (별명)
int& r = a;
r = 20; // "a의 별명인 r의 값을 20으로 바꿔라" (a 자체가 바뀌는 것과 동일)
이게 무슨 소리야..?
#include <iostream>
#include <string>
class Fruit { // '과일'이라는 추상적 개념 (Concept)
public:
std::string name; // 여기가 클래스
};
int main() {
// '과일'이라는 개념의 첫 번째 실제 사례(Instance)
Fruit apple;
apple.name = "Apple";
// '과일'이라는 개념의 두 번째 실제 사례(Instance)
Fruit banana;
banana.name = "Banana";
// "There are two instances of the Fruit class."
// (Fruit 클래스의 인스턴스가 두 개 있습니다 = 과일의 사례가 두 개 있습니다.)
return 0;
}
객체와 인스턴스의 구분은 여기서 말장난으로 느껴진다.
C++에서는 입력과 출력을 위해 cin과 cout이라는 두 개의 미리 정의된 객체를 사용한다.
이들은 각각 istream과 ostream 클래스의 속성으로 생성된 객체이다. istream과 ostream 클래스는 iostream파일에 정의되어 있다. 이 클래스들은 입력과 출력을 연속된 문자들의 스트림(stream) 이라고 간주한다. 삽입(insertion) 연산자(<<)는 ostream클래스에 정의되어 있으며, 데이터를 출력 스트림에 삽입한다. 추출(extraction) 연산자(>>)는 istream 클래스에 정의되어 있으며, 입력 스트림으로부터 정보를 추출한다.
cin과 cout은 잘 짜여진 영리한 객체이기 때문에, 프로그램의 문맥에 따라 한 형식을 다른 형식으로 자동으로 변환할 수 있다.
// hexoct1.cpp -- shows hex and octal literals
#include <iostream>
int main()
{
using namespace std;
int chest = 42; // decimal integer literal
int waist = 0x42; // hexadecimal integer literal
int inseam = 042; // octal integer literal
cout << "Monsieur cuts a striking figure!\n";
cout << "chest = " << chest << " (42 in decimal)\n";
cout << "waist = " << waist << " (0x42 in hex)\n"; // 출력은 10진수로 됨 = 66
cout << "inseam = " << inseam << " (042 in octal)\n"; // = 34
// cin.get();
return 0;
}
위 경우에는 10진수로만 출력된다.
// hexoct2.cpp -- display values in hex and octal
#include <iostream>
using namespace std;
int main()
{
using namespace std;
int chest = 42;
int waist = 42;
int inseam = 42;
cout << "Monsieur cuts a striking figure!" << endl;
cout << "chest = " << chest << " (decimal for 42)" << endl;
cout << hex; // 진법을 바꾸는 조정자
cout << "waist = " << waist << " (hexadecimal for 42)" << endl;
cout << oct; // 진법을 바꾸는 조정자
cout << "inseam = " << inseam << " (octal for 42)" << endl;
// cin.get();
return 0;
}
count << hex/oct 를 하니, 16진수와 8진수로 출력되었다.

출처: cppreference
wow🤔 sizeof는 사실 함수가 아니라 연산자다. 그래서 expression인 경우 괄호를 생략할 수 있다.
cout << "int is " << sizeof (int) << " bytes." << endl;
cout << "short is " << sizeof n_short << " bytes." << endl;
cout << "long is " << sizeof n_long << " bytes." << endl;
cout << "long long is " << sizeof n_llong << " bytes." << endl;
💡 기호 상수를 define으로 정의하지 말고, const 제한자를 사용해서 정의하라. → 이것이 C++
왜 좋냐고?
// const 데이터형 상수 이름 = 값;
// 관행 중에 하나는 상수이름은 대문자로 한다.
const int MONTHS = 12;
| 구분 | #define (과거의 방식) | const (현대적 방식) |
|---|---|---|
| 동작 메커니즘 | 전처리기가 단순히 텍스트를 찾아 치환함 | 컴파일러가 변수로 인식하고 처리함 |
| 타입 안전성 | 데이터 타입을 가지지 않음 | 명시적인 데이터 타입을 가져 타입 체크 가능 |
| 디버깅 편의성 | 기호 테이블에 이름이 남지 않아 디버깅 시 식별 불가 | 기호 테이블에 이름과 값이 기록되어 디버깅이 용이함 |
| 유효 범위 (Scope) | 정의된 시점부터 파일 끝까지 유효 (전역적) | 특정 함수나 블록{} 내로 유효 범위를 제한 가능 |
| 메모리 활용 | 치환될 때마다 코드의 복사본이 생길 수 있음 | 실제 메모리 공간을 차지하여 효율적으로 관리됨 |
// floatnum.cpp -- floating-point types
#include <iostream>
int main()
{
using namespace std;
cout.setf(ios_base::fixed, ios_base::floatfield); // fixed-point
float tub = 10.0 / 3.0; // good to about 6 places(3.333333)
double mint = 10.0 / 3.0; // good to about 15 places
const float million = 1.0e6;
cout << "tub = " << tub;
cout << ", a million tubs = " << million * tub;
cout << ",\nand ten million tubs = ";
cout << 10 * million * tub << endl;
cout << "mint = " << mint << " and a million mints = ";
cout << million * mint << endl;
// cin.get();
return 0;
}
float형이 double형보다 정밀도가 얼마나 떨어지느냐

장점
단점
cout.setf(ios_base::fixed, ios_base::floatfield); // 이거 뭐쥬?
실수를 출력할 때 소수점 자릿수를 고정하고, 지수 표기법을 쓰지 않겠다는 선언이다!
set flags 약자. 정밀도가 소수점 아래 자릿수를 의미하도록 강제한다.
-> 적어도 이게 틀린 것일 수도 있다고 인지하고 있어야 한다.
double x = 0.1 + 0.2
if (x == 0.3) // 이 조건문은 참일 수도 있고, 거짓일 수도 있다. -> 근사치니까.
정말 그럴까?
#include <iostream>
#include <iomanip> // 소수점 출력 정밀도 조절을 위해 필요
#include <cmath> // std::abs() 함수를 위해 필요
int main() {
using namespace std;
double x = 0.1;
double y = 0.2;
double sum = x + y;
double target = 0.3;
// 1. 일반적인 출력 (기본 설정으로는 0.3처럼 보임)
cout << "일반 출력: " << sum << endl;
// 2. 정밀도를 높여서 출력 (숨겨진 오차 발견)
// setprecision(17)을 사용하는 이유는 double의 유효 숫자가 약 15~17자리이기 때문
cout << fixed << setprecision(20);
cout << "0.1의 실체: " << x << endl;
cout << "0.2의 실체: " << y << endl;
cout << "합계(sum) : " << sum << endl;
cout << "대상(target): " << target << endl;
cout << "---------------------------------------" << endl;
// 3. 직접 비교 테스트
if (sum == target) {
cout << "결과: sum과 0.3은 정확히 같습니다." << endl;
} else {
cout << "결과: sum과 0.3은 다릅니다!" << endl;
cout << "두 값의 차이: " << sum - target << endl;
}
return 0;
}
