C++ 速習チートシート(第一章 基本文法編)
初めに
この記事の内容は、AtCoder Programming Guide for beginners(APG4b) の第一章の内容を素早く参照するためにまとめたものです。APG4bはAtCoderのアカウントを作れば無料で利用することができます。良くまとまっていてわかりやすいので、初めて勉強する方に大変おすすめです!(媚びを売っていくスタイル)
実行環境
目次
- 初めに
- 目次
- おまじない
- コメントアウト
- 出力
- 四則演算
- 変数の宣言
- 入力
- 比較演算子
- 論理演算子
- if文
- 変数のスコープ
- for文とwhile文
- 文字列
- 配列
- STLの関数
- 配列を渡す形式
- 細かい話
- 関数
- 関数を自分で定義する理由
- 注意点
- 細かい話
- main関数
おまじない
とりあえず何も考えないで、最初はこれをコピペしましょう。 int main(){} の{}の中に実行したいコードを書きます。
#include <bits/stdc++.h> using namespace std; int main() { }
細かい話
#include <bits/stdc++.h>
#include <bits/stdc++.h>はc++の機能をすべて読み込むという意味です。それぞれの機能を個別に読み込むことも可能で、例えば、coutやendlという命令は、#include <iostream>というところに入っています。最初のうちは、ややこしいので、#include <bit/stdc++.h>ですべて読み込んでしまいましょう。
using namespace std;
using namespace std;はプログラムを短く書くための命令です。#includeで読み込んだcoutやendlを使うためには、通常std::coutやstd::endlと書かなければなりませんが、using namespace std;を使うことでこのstd::の部分を省略できます。
コメントアウト
//または/* */でコメントアウトします。
//同じ行の以降の分がコメントアウトされます。 /* 挟まれている部分がすべてコメントアウトされます。 複数の行にまたがっていても大丈夫です。 */
出力
c++で出力するにはcoutを使います。下の例では、coutに<<で"Hello, world!"という文字列を入れ、その後改行を意味するendlという命令を送っています。文の終わりには;が必要になるので注意してください。(c++では、ほとんどの構文は文末に;を要求します。)
#include <bits/stdc++.h> using namespace std; int main() { cout << "Hello, world!" << endl; }
出力
Hello, world!
複数の出力
下のように複数の文字列や数字を出力することもできます。
#include <bits/stdc++.h> using namespace std; int main() { cout << "a:"; cout << 23 << endl; cout << "b:" << 32 << endl; }
出力
a:23 b:32
四則演算
#include <bits/stdc++.h> using namespace std; int main() { cout << 1 + 1 << endl; // 2 cout << 3 - 4 << endl; // -1 cout << 2 * 3 << endl; // 6 cout << 7 / 3 << endl; // 2 cout << 7.0/3.0 << endl; // 2.333... //剰余演算子(あまりを計算) cout << 7%3 << endl; // 1 }
変数の宣言
型 | 書き込むデータの種類 |
---|---|
int | 整数 |
double | 小数 |
string | 文字列 |
#include <bits/stdc++.h> using namespace std; int main() { int i = 10; double d = 0.5; string s = "Hello"; cout << i << endl; cout << d << endl; cout << s << endl; }
実行結果
10 0.5 Hello
注意点
異なる方同士の演算
- int と double の演算はdoubleになります。
- intやdouble と string の演算は型が合わないためコンパイルエラーになります。
異なる型同士の代入
- 計算と同様に、変換できる型同士の場合は変換されて代入されます。(double→intの場合は小数点以下切り捨て。)
- 変換できない型の場合は、コンパイルエラーになります。(stringとint等)
入力
入力を受け取るためには、cinと>>を使います。
#include <bits/stdc++.h> using namespace std; int main() { int a; // 変数aで入力を受け取る cin >> a; cout << a * 10 << endl; }
入力
5
出力
50
つなげて入力
入力が複数ある場合、>>をつなげて入力を受け取ることができます。 入力がスペースか改行で区切られている場合、分割して受けとってくれます。
#include <bits/stdc++.h> using namespace std; int main() { int a, b, c; cin >> a >> b >> c; cout << a * b * c << endl; }
入力
2 3 4
a=2,b=3,c=4と代入されます。 出力
24
比較演算子
演算子 | 意味 |
---|---|
x == y | xとyが等しい |
x!= y | xとyが等しくない |
x > y | xがyより大きい |
x < y | xがyより小さい |
x >= y | xがy以上 |
x <= y | xがy以下 |
論理演算子
演算子 | 意味 |
---|---|
!(条件式) | 条件式の否定 |
条件式1 && 条件式2 | 条件式1が真かつ条件式2が真 |
条件式1 || 条件式2 | 条件式1が真または条件式2が真 |
if文
if文は、
if(条件式){
処理
}
の形で書きます。
#include <bits/stdc++.h> using namespace std; int main() { int x; cin >> x; if (x < 10) { cout << "xは10より小さい" << endl; } cout << "終了" << endl; }
入力
5
出力
xは10より小さい 終了
前の条件が真でないとき
else文やelse if文を使います。
else文は前のif文の処理が偽のときに実行されます。
if (条件式1) { 処理1 } else { 処理2 }
else if文は前のif文の条件式が偽かつelse if文の条件式が真の場合に実行されます。
if (条件式1) { 処理1 } else if (条件式2) { 処理2 }
変数のスコープ
main関数やif文で出てくる{}で囲われたところをブロックといいます。
あるブロックで宣言された変数はそのブロックとそれより内側のブロックでしか使えないというルールがあります。この変数が使用できるの範囲のことをスコープといいます。
異なるスコープでは、同じ名前の変数を宣言することができます。
スコープが重なっている場合
あるブロックで宣言した変数
#include <bits/stdc++.h> using namespace std; int main() { int x = 5; cout << x << endl; // 5 if (x == 5) { cout << x << endl; // 5 string x = "hello"; // int x = 5;のスコープと重なっている cout << x << endl; // hello } cout << x << endl; // 5 }
出力
5 5 hello 5
この挙動はしばしばバグの原因となるため気を付けてください。
for文とwhile文
for文とwhile文はどちらも繰り返し処理を書きたいときに使います。
while文
#include <bits/stdc++.h> using namespace std; int main() { // iを0からはじめる int i = 0; // iが5未満の間ループ while (i < 5) { cout << "Hello" << endl; //繰り返したい処理 i++; } }
for文
for文は以下のように書き、条件式が真である限り処理を繰り返します。
for (初期化; 条件式; 更新) {
処理
}
continueとbreak
- continue;はfor文の残りの処理をスキップして、次のループに入るという命令です。
- break;は今いるfor文から抜け出すという命令です。
for文の()の省略
for文の(初期化;条件式;更新)の部分は省略することが可能です。
初期化の省略
あらかじめ存在する変数をカウンタ変数に使用したい場合は、初期化が不要です。その場合例えば次のように書きます。
int i = 0;//カウンタ変数として使用 for (; i < n;) { //初期化を省略 i++; }
条件式の省略
条件式を省略した場合、条件式は常にtrueとして扱われます。たとえば、次のプログラムは無限ループとなります。
for (int i = 0; ; i++) { cout << i << endl; }
for文とwhile文の違い
for文とwhile文では主に二つの点で異なります。
カウンタ変数のスコープの違い whille文では、while文の前にカウンタ変数を宣言する必要があるため、カウンタ変数のスコープははその宣言がなされてから、while文の書かれているブロックが終わるまでとなります。一方for文では、カウンタ変数のスコープはfor文の中だけです。
continue;の動作への注意 while文では、インクリメントの前にcontinue;を入れてしまうと、カウンタ変数が更新されず、無限ループになってしまいます。
文字列
文字列を扱うには、string型の変数を使います。
文字列の長さの取得
文字列の長さは、文字列変数.size()で取得できます。これはメンバ関数というクラスを利用しています。
i番目の文字
i番目の文字の取得は、文字列変数.at(i)でできます。iは0から始まることに注意してください。
文字(char型)
文字列の型として、string型がありますが、文字の型というものも存在していて、charという型を使います。string型と違って、char型は一文字分のデータしか保持することができません。
string型を表すのに""で囲ったように、char型を表すのには、''(シングルクォート)で囲みます。
#include <bits/stdc++.h> using namespace std; int main() { char c = 'a'; cout << c << endl; // a }
文字列変数.at(i)の型
文字列変数.at(i)の型はchar型です。
文字列の書き換え
文字列の一部を書き換えるときは、char型を使う必要があります。
#include <bits/stdc++.h> using namespace std; int main() { string str = "Hello"; str.at(0) = 'M'; // char型の'M' cout << str << endl; // Mello }
出力
Mello
注意点
全角文字の取り扱い
c++では、string型やchar型では、全角文字は文字化けしてしまい、うまく扱うことができません。全角文字を扱うには、string型ではない別の型を使う必要があります。(u32string等)
文字列のメンバ関数や演算子を利用するとき
"文字列".size()や後述する==演算子を利用するとき、一度変数に格納するか、"文字列".ssize()のように一度sを付ける必要があります。そうしないとコンパイルエラーになります。
#include <bits/stdc++.h> using namespace std; int main() { string str = "Hello"; cout << str.size() << endl; // 5 cout << "Hello"s.size() << endl; // 5(sを末尾につける) cout << "Hello".size() << endl; // できない }
文字列の比較
string型にも数値型のような比較演算子が定義されています。
演算子 | 意味 |
---|---|
== | 二つの文字列が完全に一致 |
!= | 二つの文字列に違いがある |
<, <=, >, >= | 辞書順による比較 |
辞書順というのは、文字通り辞書に載っている順番のことです。
c++の順序では'0'~'9'→'A'~'Z'→'a'~'z'の順になっています。
例えば、"012"s < "ABC"s == trueであり"ABC"s < "xyz"s == trueです。
文字列の連結
+演算子を使うと文字列を連結することができます。ただし、数値型のように-,*,/は定義されていないので注意しましょう。
#include <bits/stdc++.h> using namespace std; int main() { string hello = "Hello"; // +演算子による連結 cout << hello + ", world!" << endl; // Hello, world! // +=演算子による連結 hello += ", Lime!"; cout << hello << endl; // Hello, Lime! }
出力
hello, world! Hello, Lime!
string型とchar型
- string型とchar型の比較はできません。
- string型とchar型を+演算子で連結することはできます。
char型の変数への入力
cinでchar型の変数に入力を格納すると、1文字ずつ値を入れることができます。
#include <bits/stdc++.h> using namespace std; int main() { char a, b; cin >> a >> b; cout << a << endl; cout << b << endl; }
入力
OK
出力
O K
エスケープシーケンス
改行などの特殊な文字を利用する場合、エスケープシーケンスを利用します。 エスケープシーケンスとして例えば以下のようなものがあります。
エスケープシーケンス | 意味 |
---|---|
\n | 改行 |
\" | ダブルクォート |
\' | シングルクォート |
\ | バックスラッシュ() |
\t | タブ |
\r | 復帰 |
#include <bits/stdc++.h> using namespace std; int main() { cout << "こんにちは\nLime"; }
出力
こんにちは Lime
行単位での入力
cinを使うとスペースを区切りにして、簡単に入力を受け取ることができますが、場合によっては、行単位で入力を受け取りたいときもあります。その場合はgetlineを使います。
#include <bits/stdc++.h> using namespace std; int main() { string s, t; getline(cin, s); // 変数sで入力を一行受け取る getline(cin, t); // 変数tで入力を一行受け取る cout << "一行目 " << s << endl; cout << "二行目 " << t << endl; }
入力
I have a pen. I have an apple.
出力
一行目 I have a pen. 二行目 I have an apple.
配列
文字列を格納するための変数として、string型がありましたが、これはchar型をリストにしたものとみなすこともできます。これと同じように考えて、ある変数の型のリストとして、配列というものを考えることができます。 配列の宣言は次のようにして行います。
vector<型> 配列変数名;
また配列に値を代入する方法はいくつかありますが、その一つとして下のような方法があります。
配列変数 = { 要素1, 要素2, ... };
例
#include <bits/stdc++.h> using namespace std; int main() { // 文字列 string str; // 文字列変数を宣言 str = "abcd"; // 'a', 'b', 'c', 'd' という文字(char)の列を代入 cout << str.at(0) << endl; // 1つ目である'a'を出力 cout << str.size() << endl; // 文字列の長さである4を出力 // 配列 vector<int> vec; // int型の配列変数vecを宣言 vec = { 25, 100, 64 }; // 25, 100, 64 という整数(int)の列を代入 cout << vec.at(0) << endl; // 1つめである25を出力 cout << vec.size() << endl; // 配列の長さである3を出力 }
配列が持つ一つ一つのデータのことを要素といいます。
また、文字列と同様に、.size()を使うことで配列の長さが取得でき、.at(i)を使うことでi番目の要素にアクセスすることができます。
配列の初期化
次のように書くと、指定したサイズで配列が初期化されます。どんな値で初期化するかは、要素の型によって変わります。
vector<型> 配列名(要素数);
初期値の指定
次のように書くと配列の初期値を指定できます。
vector<型> 配列名(要素数, 初期値);
例えば、vector
配列変数への入力
配列変数で入力を受け取るには、十分大きな変数で配列を初期化した後、.at(i)で一つずつ入力していく必要があります。
// 3個の入力を受け取れるように 3要素の配列 {0, 0, 0} で初期化 vector<int> vec(3); // atを使って1つずつ入力 cin >> vec.at(0) >> vec.at(1) >> vec.at(2);
要素の追加
配列は文字列のときのように+=を使って要素を追加することができません。しかし、その代わりに、"配列変数".push_back()を使って、配列の末尾に要素を追加することができます。
#include <bits/stdc++.h> using namespace std; int main() { vector<int> vec = { 1, 2, 3 }; vec.push_back(10); // 末尾に10を追加 // vecの全要素を出力 for (int i = 0; i < vec.size(); i++) { cout << vec.at(i) << endl; } }
出力
1 2 3 10
また、要素の削除は"配列変数名".pop_back()をつかうことでできます。
配列同士の比較
文字列と同様に配列の比較も==を使って、行うことができます。
==では左辺と右辺の全要素が一致しているときのみtrueになり、それ以外はfalseとなります。
また、配列変数同士の比較のみ可能で、例えば{1, 2, 3}という記法はコンパイルエラーになります。
#include <bits/stdc++.h> using namespace std; int main() { vector<int> vec1 = { 1, 2, 3 }; vector<int> vec2 = { 1, 2, 3 }; if (vec1 == vec2) { cout << "OK" << endl; } /* ↓これはコンパイルエラーになる if (vec1 == { 1, 2, 3 }) { cout << "NG" << endl; } */ }
STLの関数
## STLの関数とは何か? C++にデフォルトで用意されている関数。以下のようにして呼び出せる。
関数名(引数1, 引数2, ...)
STLの関数の例
・min(a,b) aとbのうち大きくないほうを返す。 ・max(a,b) aとbのうち小さくないほうを返す。 ・swap(a,b) aとbの値を入れ替える。
配列を引数にする関数
reverse関数
reverse関数を使うと配列の要素の並びを逆にできます。
reverse関数には返り値がないことに注意してください。
#include <bits/stdc++.h> using namespace std; int main() { vector<int> vec = {1, 5, 3}; reverse(vec.begin(), vec.end()); // {3, 5, 1} for (int i = 0; i < vec.size(); i++) { cout << vec.at(i) << endl; } }
sort関数
sort関数は配列の要素を小さい順に並び替えます。
sort関数にも返り値はありません。
#include <bits/stdc++.h> using namespace std; int main() { vector<int> vec = {2, 5, 2, 1}; sort(vec.begin(), vec.end()); // {1, 2, 2, 5} for (int i = 0; i < vec.size(); i++) { cout << vec.at(i) << endl; } }
配列を渡す形式
STLの関数に配列を渡すときは、次の形式で渡すことが多いです。
関数名(配列変数.begin(), 配列変数.end())
細かい話
引数の実行順序
引数の実行順序は環境によって異なります。例えば、GCC,C++14では次のように後ろの引数から処理が行われます。
min(1 + 1, 2 + 2) ↓ min(2, 2 + 2) ↓ min(2, 4) ↓ 2
関数
関数は自分で作ることもできます。関数を作成することを関数を定義するといいます。
次の例では、STLの関数のminと同じ動きをする、関数my_minを定義しています。
#include <bits/stdc++.h> using namespace std; // 関数定義 int my_min(int x, int y) { if (x < y) { return x; } else { return y; } } int main() { int answer = my_min(10, 5); cout << answer << endl; // 5 }
関数の定義
関数の定義はmain関数より前で行います。
関数の記法は以下の通りです。
返り値の型 関数名(引数1の型 引数1の名前, 引数2の型 引数2の名前, ...) { 処理 }
返り値は次のようにreturn文で指定します。
return 返り値;
返り値がない関数
関数の返り値がない場合の存在します。
その場合は、返り値の型にvoidを指定します。返り値の型がvoidである関数のreturn文は次のように書きます。
return;
引数がない関数
関数の引数が不要な場合は、定義と呼び出しでは、()とだけ書きます。
#include <bits/stdc++.h> using namespace std; // 整数の入力を受け取って返す関数 // 引数なし int input() { int x; cin >> x; return x; } int main() { int num = input(); // 引数なし cout << num + 5 << endl; }
関数を自分で定義する理由
主に次のような3つの理由があります。
- プログラムの重複が避けられる。
- 処理の塊に名前を付けられる。
- 再帰関数が書ける。
注意点
rturn文の動作
処理がreturn文の行に到達した時点関数の処理は終了してしまいます。
返り値の指定忘れ
返り値がある関数で返り値を指定し忘れると、どんな値が返ってくるかわかりません。エラーにならないので注意しましょう。
引数はコピーされる
他の変数に値を渡した時と同様に、基本的に引数に渡した値はコピーされます。
#include <bits/stdc++.h> using namespace std; // 引数の値に5を足して出力する関数 void add5(int x) { x += 5; cout << x << endl; return; } int main() { int num = 10; add5(num); // numの値は引数xにコピーされる cout << num << endl; // numは10のまま }
出力
15 10
関数が呼び出せる範囲
関数は宣言した後でしか呼び出せません。宣言するより前に関数を呼び出すとコンパイルエラーになります。
細かい話
プロトタイプ宣言
プロトタイプ宣言をすれば関数を定義する前に呼び出すことができます。プロトタイプ宣言とは、関数の名前と引数と返り値の型だけを先に宣言することです。
#include <bits/stdc++.h> using namespace std; // プロトタイプ宣言 void hello(); int main() { // プロトタイプ宣言をしたので呼び出せる hello(); } void hello() { cout << "hello!" << endl; return; }
引数名の省略
引数の名前は省略することができます。例えば、my_minのプロトタイプ宣言は次のように書くこともできます。
int my_min(int, int);
returnの省略
返り値がない場合、関数の末尾では、returnを省略できます。
main関数
初めのプログラムから出ていたmain関数も関数の一つです。
ただし、main関数は特別扱いされていて、returnを省略した場合は必ず0が返るようになっています。