はじめに
こんにちは、42Tokyoの一般生徒ことsamatsumです。
この記事は、C言語の基礎がわかっている方を対象に、「Hello World」を通じてC++の基礎を解説していきます。
まぁ42生徒向けってことでさ。
一回技術ブログってのを書いてみたかったんですよね。
CPP00~09に必要な知識や「良い」コードの書き方を書き連ねていくプロジェクト第一弾です。
応援してね~。
この記事を読み終える頃には、以下のコードの意味が余すことなく理解できるようになります。
#include <iostream>
int main() {
std::cout << "Hello World" << std::endl;
return 0;
}
「こんだけ~?」と思うかもしれませんが、少しでも分からない所が有るなら読む価値ありますよマジで。
目次
C言語とC++、出力の違い
C言語(おなじみ)
#include <stdio.h>
int main() {
printf("Hello World\n");
return 0;
}
C++
#include <iostream>
int main() {
std::cout << "Hello World" << std::endl;
return 0;
}
初めて見ると「何じゃらホイ?」ですよね。
std::coutって何? <<って何? std::endlって何?
安心してください、解説しますよ(とにかく解説する安村)。
まずはC++で新しく学ぶ、ストリームという仕組みから。
ストリームって何?
C言語の入出力の問題
C言語では、出力先によって使う関数を変えなければなりませんでした。
| 出力先 | C言語の関数例 |
|---|---|
| 標準出力(stdout) | printf("Hello") |
| ファイル | fprintf(fp, "Hello") |
| メモリ(文字列バッファ) | sprintf(buf, "Hello") |
出力先が異なれば関数も異なる。しかも引数の形も違う。
めんどくさいよね~~~。
C++の解決策:ストリーム
C++では「ストリーム(stream=流れ)」という仕組みでこれを解決します。
考え方はシンプル。<< の左側に置くオブジェクトが、データの届け先を決めます。
std::cout << "Hello"; // → 標準出力(端末画面)に届く
file << "Hello"; // → ファイルに届く
oss << "Hello"; // → メモリ上の文字列に届く
図にするとこんな感じ。
【どこに届ける?】 【どうやって?】 【何を届ける?】
cout << "Hello World"
file << "Hello World"
oss << "Hello World"
~~~~~~~~~~~~ ~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
ここだけ変える いつも同じ! いつも同じ!
C言語では関数名を変えて出力先を切り替えていました(printf、fprintf、sprintf)。
C++ではオブジェクトを変えるだけ。操作(<<)は常に同じです。
一見冗長に見えるかもしれないけど、理解するとC言語の面倒くささが消えた書き方だと分かります。
ちょっと待って、オブジェクトって?
ここで「オブジェクト」という言葉が出てきました。
C言語の変数は「データを入れる箱」でした。
C++のオブジェクトは「データ+そのデータに対する操作をセットにしたもの」です。
例えばcoutは、「標準出力への接続情報」と「<< でデータを送る機能」がセットになったオブジェクト。
今は「C言語のFILE *が進化したもの」くらいのイメージでOKです。…OKだよね?
具体的なコードで見てみよう
#include <iostream> // coutとendl を使うため
#include <fstream> // ofstream(ファイル出力)を使うため
#include <sstream> // ostringstream(メモリ出力)を使うため
int main() {
// ① 標準出力に出力(cout は C++版の stdout)
std::cout << "Hello World" << std::endl;
// ② ファイルに出力
std::ofstream file("output.txt");
file << "Hello World" << std::endl;
// ③ メモリ上の文字列に出力
std::ostringstream oss;
oss << "Hello World" << std::endl;
return 0;
}
① std::cout は標準出力への専用オブジェクト。C言語のstdoutに相当します。
② std::ofstream は「output file stream」の略。C言語ではfopen()→fprintf()と2ステップ必要でしたが、C++では1行でファイルを開いてオブジェクトを作成できます。あとはcoutと同じ<<で書き込むだけ。
③ std::ostringstream は「output string stream」の略。データをメモリ上の文字列に溜め込むオブジェクトです。C言語のsprintf(buf, ...)に相当しますが、バッファサイズを気にしなくてOK(自動で伸びます)。
どの行も オブジェクト << データ という同じ形。これがストリームの力です。
まとめ:ストリームでは
<<の左側のオブジェクトが届け先を決める。届け先が変わっても、データの流し方(<<)は変わらない。
cout や endl の名前の由来
ストリームの仕組みがわかったところで、名前の由来を押さえておきましょう。覚えやすくなります。
| 名前 | 由来 | 意味 |
|---|---|---|
cout |
Character OUTput | 標準出力(stdout)へのストリーム |
cin |
Character INput | 標準入力(stdin)からのストリーム |
cerr |
Character ERRor | 標準エラー出力(stderr)へのストリーム |
endl |
END Line | 行の終わり(改行+フラッシュ) |
iostream |
Input Output STREAM | 入出力ストリーム |
補足:
coutはC++版のstdout、cinはC++版のstdinだと思えばOKです。
つまり std::cout << "Hello" << std::endl; は、日本語で読むとこ~んな感じ。
「標準ライブラリ(std)の標準出力ストリーム(cout)に、"Hello"を流し込み(<<)、さらに行の終わり(endl)を流し込む(<<)」
<< 演算子の形にも注目。データが左に向かって流れていく矢印のように見えませんか?
名前空間(namespace)って何?
std::coutのstd::って?
std::cout << "Hello World" << std::endl;
-
std→ **名前空間(namespace)**の名前 -
::→ スコープ解決演算子(「〇〇に所属する」という意味) -
cout→ 標準出力ストリーム・オブジェクト -
endl→ 改行+バッファフラッシュを行うマニピュレータ
つまり std::cout は「stdという名前空間にあるcout」という意味です。
なぜ名前空間が必要なの?
プログラムが大きくなると、変数名や関数名が他のライブラリと衝突する問題が起きます。
「山田さん」が100人いる会社では、「東京オフィス○○課の山田さん」「大阪オフィス××課の山田さん」と所属をつけて区別しますよね。
名前空間はこの「所属」にあたるものです。
// std(標準ライブラリ)の中のcout
std::cout << "Hello" << std::endl;
// mylib(オリジナルライブラリ)の中のcout
mylib::cout << "Hello" << mylib::endl; // 衝突しない!
using namespace std; は使わないべき?
using namespace std; // これを書くと std:: を省略できる
cout << "Hello World" << endl; // std:: 不要!
便利ですが、実務では推奨されません。
- せっかく名前の衝突を防ぐための名前空間なのに、省略したら意味がない
- 大規模プロジェクトで予期しない名前衝突が起きるリスクがある
- 特にヘッダファイルで使うと、インクルードした全てのファイルに影響してしまう
42Tokyoの課題でも using namespace は禁止されていることが多いです。
面倒でも std:: をつける癖をつけましょう!
std::endl と \n の違い
一見同じように見えますが、実は動作が異なります。
std::cout << "Hello World" << std::endl; // 改行 + バッファフラッシュ
std::cout << "Hello World\n"; // 改行のみ
std::endl |
\n |
|
|---|---|---|
| 改行 | ✅ | ✅ |
| バッファフラッシュ | ✅ | ❌ |
| 処理速度 | 遅い | 速い |
バッファフラッシュとは?
printfを使ったとき、データが一旦**バッファ(一時的な保管場所)**に溜まってから出力されていたのを覚えていますか?
C++のストリーム(std::cout)も同じくバッファリングされています。
そのバッファをいつ吐き出す(フラッシュする)かに関わるのが、\nとstd::endlの違いです:
-
\n→ バッファに改行を追加するだけ(フラッシュはしない) -
std::endl→ バッファに改行を追加した上で、中身を全て吐き出す(フラッシュする)
つまりどちらもバッファの上で動いているのは同じで、フラッシュするかしないかが違うということです。
💡 補足:標準出力が端末に接続されている場合、
\nでも自動的にフラッシュされることが多いです(行バッファリング)。違いが顕著になるのはファイルにリダイレクトしたときなどです。
まとめ
| C言語 | C++ | ポイント |
|---|---|---|
printf |
std::cout |
ストリームで統一的に入出力できる |
\n |
std::endl or \n
|
バッファに貯めるか吐き出すか |
| ― | std:: |
名前の衝突を防ぐ |
C言語からC++に移行する最初の一歩は、「関数ベースの入出力」から「ストリームベースの入出力」への考え方の切り替えです。
最初はstd::coutが冗長に感じるかもしれませんが、C++の設計思想を理解すれば、その合理性がわかるはずです。
次の記事はコチラ!classについての解説ですよ〜。
この記事は 42Tokyo でのC++学習をもとに作成しました。
簡単な記事だし1時間で書き終わるやろ…とか思ってたら3時間かかってら。
いいね(?)とかで応援してくれると記事の投稿スピードがアップするかもしれないとも言い切れないかもしれないような気がするぞ!