競プロ中にハマった C++ の取扱い注意点
更新日 : 2020-03-23
注意
自分は、競技プログラミング以外では一切 C++ を使っていません。
はじめに
自分が言語仕様を正しく理解していないため、競プロ中に「何故このコードが WA なの?」がたまに発生します。
この記事では、実際に自分がハマった事例、その解決 (解決というより解消?) 方法を載せていきます。
「言語仕様を勉強しろ」なのですが、それは一旦無視します。
この記事は、気が向いたときに更新します。
vector
トラブル : 配列の各要素に 1 を加算したいのに...
#include <bits/stdc++.h> using namespace std; int main() { vector<int> A = { 1, 2, 3 }; for (int v : A) v++; cout << A.at(0) << " " << A.at(1) << " " << A.at(2) << endl; // 2 3 4 と出るはず... }
1 2 3
変数 v
には配列の値のコピーが格納されているため、v
(コピー) に変更を加えても配列の値 (オリジナル) には影響しません。
- 対処 (その 1)
#include <bits/stdc++.h> using namespace std; int main() { vector<int> A = { 1, 2, 3 }; for (int i = 0; i < 3; i++) A.at(i)++; cout << A.at(0) << " " << A.at(1) << " " << A.at(2) << endl; }
2 3 4
配列の各要素にアクセスしています。
- 対処 (その 2)
#include <bits/stdc++.h> using namespace std; int main() { vector<int> A = { 1, 2, 3 }; for (int &v : A) v++; // 参照 cout << A.at(0) << " " << A.at(1) << " " << A.at(2) << endl; }
2 3 4
範囲 for 文での参照については、AtCoder の C++入門 APG4b の 2.04.参照 にて説明されています。
こんな感じで、このあとも淡々と挙げていきます。
トラブル : 配列の各要素に関数を作用させたいのに...
#include <bits/stdc++.h> using namespace std; // val を m で割った余りを返す (余りが負になったら m を足す) long long mod(long long val, long long m) { long long res = val % m; if (res < 0) res += m; return res; } int main() { vector<int> A = { -1, 0, 1 }; for (int i = 0; i < 3; i++) { mod(A.at(i), 1000000007); } cout << A.at(0) << " " << A.at(1) << " " << A.at(2) << endl; // 1000000006 0 1 と出るはず... }
-1 0 1
配列の各要素に関数の返り値が格納されていません。
- 対処
#include <bits/stdc++.h> using namespace std; long long mod(long long val, long long m) { long long res = val % m; if (res < 0) res += m; return res; } int main() { vector<int> A = { -1, 0, 1 }; for (int i = 0; i < 3; i++) { A.at(i) = mod(A.at(i), 1000000007); } cout << A.at(0) << " " << A.at(1) << " " << A.at(2) << endl; }
1000000006 0 1
配列の各要素に関数の返り値を格納しています。
関数の引数に値を渡すことについては、C++入門 APG4b の 1.15.関数 にて説明されています。
その他
トラブル : 演算子の優先順位
#include <bits/stdc++.h> using namespace std; int main() { int a = 1, b = 2, c = 3; if (a ^ b ^ c == 0) cout << "Yes" << endl; if (a ^ b ^ c != 0) cout << "No" << endl; // a ^ b ^ c は 0 だから、Yes のみ出力されるはず... }
Yes No
演算子の優先順位は ^
よりも ==
の方が高いです。a ^ b ^ (c == 0)
は 3 で、a ^ b ^ (c != 0)
は 2 です。
- 対処
#include <bits/stdc++.h> using namespace std; int main() { int a = 1, b = 2, c = 3; if ((a ^ b ^ c) == 0) cout << "Yes" << endl; if ((a ^ b ^ c) != 0) cout << "No" << endl; }
Yes
とりあえずカッコをつけます。演算子の優先順位については、C++の演算子の優先順位 - cppreference.com などで確認できます。