C - 1.02.プログラムの書き方とエラー Editorial /

Time Limit: 0 msec / Memory Limit: 0 KB

前のページ | 次のページ

キーポイント

  • スペース・改行・インデントを使ってプログラムを見やすくする
  • プログラムは「書く→実行→正しく動作することを確認」で初めて完成と言える
  • コンパイルエラーは文法のエラーで、プログラムは実行されない
  • 実行時エラーは内容のエラーで、プログラムは強制終了される
  • 論理エラーは内容のエラーで、プログラムは正しく動いているように見えてしまう
  • エラーは「実行して動作を確認する」「Webで検索する」等して修正する
  • エラーの大まかな発生箇所は./Main.cpp:行:文字目: errorからわかる
  • エラーメッセージが複数表示された場合は最初のエラーから直す

プログラムの書き方

プログラム中のスペースと改行、およびインデントについて説明します。
これらを使ってプログラムを読みやすくしておくと、エラーが発生した時に修正しやすくなります。

スペースと改行

C++では、基本的にスペースと改行は同じ意味になります。
また、どちらも省略できることが多いです。

以下の2つプログラムは全く同じ意味になります。

#include <bits/stdc++.h>
using namespace std;

int main() {
  cout << "a";
  cout << "b" << endl;
  cout << "c" << "d" << endl;
}
#include <bits/stdc++.h>
using namespace std;int main(){cout<<"a";cout<<"b"<<endl;cout<<"c"<<"d"<<endl;}
実行結果
ab
cd

詰め込んであるプログラムは読みづらいので、スペースと改行を多く使って読みやすく書くのが一般的です。
スペースと改行の使い方に決まったルールはありません。一例としてサンプルプログラムを参考にしてください。

インデント

行のはじめにある連続したスペースのことをインデントと言います。
スペースとインデントでプログラムの動作が変わることはありません。プログラムを見やすくするために行います。

インデントはキーボードのTabキーを押して行います。TabキーはQキーの隣にあります。

#include <bits/stdc++.h>
using namespace std;

int main() {
  //←インデント
  cout << "こんにちは世界" << endl;
}

基本的に{が出てきたら一段インデントし、}が出てきたら一段戻します。
また、元々一行に書いていたプログラムが長くなった場合は、改行してインデントすることがあります。

#include <bits/stdc++.h>
using namespace std;

int main() {
  cout << "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    << "abcdefghijklmnopqrstuvwxyz" // 長いので改行してインデント
    << endl;
}

インデントの幅はプログラムを書いている環境により異なり、スペース2個から8個分であることが多いです。
どの程度の幅を使うかは基本的に自由ですが、プログラムを読みやすくするにはインデントの幅が統一されていることが重要です。

この教材では、AtCoderのコードテストページの設定に合わせて、インデントの幅をスペース2個分にしています。

今後複雑なプログラムを書くようになった場合、インデントをしているかどうかで大きく読みやすさが変わってきます。
サンプルプログラムを参考にしっかりインデントをするようにしましょう。


プログラムのエラー

プログラムは書き終わったら完成ではありません。動かしてみてその動作が正しいことを確認して、はじめて完成と言えます。
しかし書き終えたばかりのプログラムを実行しようとすると、たいてい何らかのエラーが発生します。そのときにエラーの原因を理解して修正できることもプログラマーの重要なスキルです。

プログラムには主に3つのエラーがあります。

  • コンパイルエラー
  • 実行時エラー
  • 論理エラー

それぞれについて説明します。

コンパイルエラー

コンパイルエラーとは、書いたプログラムの文法にミスがあるときに発生するエラーです。
全角文字がプログラム中に入り込んだり、文末の;を忘れたときなどにはコンパイルエラーになります。

プログラミング言語では「文法」が厳密に決められています。
日本語などの人間が使う言語では、文法的に少し崩れた文でも意図が通じますが、プログラミング言語ではそうはいきません。

コンパイルエラーが起きた場合、プログラムは一切動作しません。

実行時エラー

「プログラムを動かす」ことを「プログラムを実行する」といいます。

実行時エラーとは、プログラムの文法に間違いはなかったが、内容に致命的な間違いがあったときに発生するエラーです。
具体的には3÷0のように、0で割り算を行ってしまった場合などに発生します。
スマホアプリやゲーム等が強制終了してしまったとき、多くの場合実行時エラーが発生しています。

実行時エラーが起きた場合、実行時エラーが起きる直前までプログラムは動作しますが、エラー以降は動かなくなってしまいます。

論理エラー

論理エラーとは、プログラムは一見正しく動作しているが、その動作が実は正しくないときに発生するエラーです。
例えば、「300円のクッキーと100円のアメを買ったときに払うお金」を計算するプログラムでは300 + 100と計算するべきですが、間違って300 - 100としてしまった場合などは論理エラーに当たります。
論理エラーは勘違いで生まれたり、タイピングのミスで発生したりと様々です。

論理エラーは一見問題なくプログラムが動作してしまうため、発見することが難しくなりやすいです。

エラーの直し方

実行してエラーや出力を確認→プログラムを修正→実行してエラーや出力を確認→... を繰り返すことが基本的な流れです。

エラーメッセージが表示される場合は、そのメッセージをコピー&ペーストしてWeb検索してみるのも手です。
特にコンパイルエラーに関しては、エラーメッセージで検索すると分かることが多々あります。

調べてみてもよくわからない場合は、わかりそうな人に質問するのも良いでしょう。


コンパイルエラーの例

コンパイルエラーのうち、よくある3つの例を紹介します。

コンパイルエラーの内容は英語で表示されますが、英語が読める必要はありません。
エラーメッセージのパターンからなんとなく原因が推測できれば十分です。

全角スペース

全角スペースを紛れ込ませてしまうケースです。

次のプログラムでは、coutの前に全角スペースが紛れ込んでいます。

#include <bits/stdc++.h>
using namespace std;

int main() {
//↓に全角スペース
 cout << "Hello, world!" << endl;
}
コンパイルエラー
./Main.cpp:6:1: error: stray ‘\343’ in program
  cout << "Hello, world!" << endl;
 ^
./Main.cpp:6:1: error: stray ‘\200’ in program
./Main.cpp:6:1: error: stray ‘\200’ in program

error: stray ‘\343’ in program(エラー: ‘\343’がプログラム中に紛れ込んでいます)というエラーメッセージが表示されています。

全角スペースのコンパイルエラーでは、stray ‘\343’ in programstray ‘\200’ in programと表示されるのが特徴です。
多くの場合、エラーメッセージがどこに全角スペースが入っているのかも教えてくれます。

上記のケースでは./Main.cpp:6:1:と書いてあり、6行目の1文字目にエラーがあることがわかります。
このように、エラーの発生箇所は./Main.cpp:行:文字目: errorを読めば特定できます。

また、エラーメッセージの2行目に

  cout << "Hello, world!" << endl;
 ^

と書いてあり、coutの前に全角スペースがあることが視覚的にもわかります。

ただし、エラーメッセージが示す位置は少しずれることもあるので注意してください。

セミコロン忘れ

セミコロン;が必要な行の末尾にセミコロンを付け忘れるケースです。

次のプログラムでは、endlの後にセミコロンを付けるのを忘れてしまっています。

#include <bits/stdc++.h>
using namespace std;

int main() {
  cout << "Hello, world!" << endl
}
コンパイルエラー
./Main.cpp: In function ‘int main()’:
./Main.cpp:6:1: error: expected ‘;’ before ‘}’ token
 }
 ^

error: expected ‘;’ before ‘}’ token(エラー: ‘}’トークンの前に‘;’が予期されます)というエラーメッセージが表示されています。

セミコロン忘れのコンパイルエラーでは、expected ‘;’ before ...というメッセージが表示されるのが特徴です。
少しわかりにくいですが、このエラーメッセージは「エラーが発生した次の行」を指し示しています。

上記のケースでは./Main.cpp:6:1: error:とあり、セミコロンを忘れた次の行である6行1文字目}の位置を指し示しています。

大量のエラー・謎のエラー

一つのミスで大量のエラーメッセージが出てくることもあります。また、エラーメッセージが直接的な原因を示していないことがあります。
その場合は一番最初のエラーが指し示している場所を見て、原因を推測しましょう。

次のプログラムではendlの直前の<<<と書いてしまっただけのミスにより、大量に謎のエラーメッセージが表示されています。

#include <bits/stdc++.h>
using namespace std;

int main() {
  cout << "hello" < endl;
}
コンパイルエラー
./Main.cpp: In function ‘int main()’:
./Main.cpp:5:19: error: no match for ‘operator<’ (operand types are ‘std::basic_ostream<char>’ and ‘<unresolved overloaded function type>’)
   cout << "hello" < endl;
                   ^
In file included from /usr/include/c++/5/regex:61:0,
                 from /usr/include/x86_64-linux-gnu/c++/5/bits/stdc++.h:108,
                 from ./Main.cpp:1:
/usr/include/c++/5/bits/regex.h:1426:5: note: candidate: template<class _Bi_iter> bool std::operator<(const std::sub_match<_BiIter>&, const typename std::iterator_traits<_Iter>::value_type&)
     operator<(const sub_match<_Bi_iter>& __lhs,
     ^
/usr/include/c++/5/bits/regex.h:1426:5: note:   template argument deduction/substitution failed:
./Main.cpp:5:21: note:   ‘std::basic_ostream<char>’ is not derived from ‘const std::sub_match<_BiIter>’
   cout << "hello" < endl;
                     ^
In file included from /usr/include/c++/5/regex:61:0,
                 from /usr/include/x86_64-linux-gnu/c++/5/bits/stdc++.h:108,
    ...

大量のエラーメッセージが表示された場合、とりあえず一番最初のエラーメッセージだけを見ると良いです。

一番最初のエラーメッセージだけを抜き出すと次のように表示されています。

./Main.cpp: In function ‘int main()’:
./Main.cpp:5:19: error: no match for ‘operator<’ (operand types are ‘std::basic_ostream<char>’ and ‘<unresolved overloaded function type>’)
   cout << "hello" < endl;
                   ^

error: no match for ‘operator<’...と書いてありますが、このエラーメッセージはあまり参考になりません。
このように、エラーメッセージが直接的な原因を示していないこともあります。

エラーメッセージの内容がよくわからない場合でも、エラーの発生箇所は参考になることが多いです。
この場合は./Main.cpp:5:19: error:と書いてあるので、5行目19文字目である次の部分でエラーが発生していることがわかります。

   cout << "hello" < endl;
                   ^

エラーの発生箇所をよく見ると、<<<と書き間違えていることがわかります。
コンパイルエラーを直す際は、エラーの発生箇所から原因を推測することも大切です。


コンパイルエラー集

付録3.コンパイルエラー集にその他のよくあるエラーについてまとめました。
コンパイルエラーの原因がわからない時に見てみてください。


問題

リンク先の問題を解いてください。