はじめての C++ プログラミング

この Notebook は,

のプログラミング部分に相当する内容を xeus-cling という Juypter kernel を利用して書いてみたものです。

xeus-cling is a Jupyter kernel for C++ based on the C++ interpreter cling and the native implementation of the Jupyter protocol xeus.

Cling は C++ のインタープリターです。 章番号はオリジナルの従来テキストに対応するように8章からはじめています。

通常の C++ のソースでは,以下のように main() でブログラム文を {} で囲みますが...

#include <iostream>
using namespace std;

int main()
{
    for(int i = 1; i <= 5; i++) {
        cout << "こんにちは, C++ の世界!   "  << i << endl;
    }
    return 0;
}

Cling は,C++ のインタープリタ実装であり,以下のように main(){ } なしで実行できます。

In [1]:
#include <iostream>
using namespace std;
In [2]:
for(int i = 1; i <= 5; i++) {
    cout << "こんにちは, C++ の世界!   "  << i << endl;
}
こんにちは, C++ の世界!   1
こんにちは, C++ の世界!   2
こんにちは, C++ の世界!   3
こんにちは, C++ の世界!   4
こんにちは, C++ の世界!   5

Cling は C プログラムも理解するようですが,最後に 13 と表示します。

In [3]:
#include <stdio.h>
printf("Hello World!\n")
Hello World!
Out[3]:
13

Cling に標準でついてくる Jupyter kernel もありますが,本稿執筆時点で,cin でエラーがでないのは,こちらの xeus-cling でした。

In [4]:
int a;
cin >> a;
cout << "今入力した整数は " << a << " ですね\n";
321
今入力した整数は 321 ですね

はじめてのプログラミング

エンゲル係数とは,家計の消費支出に占める飲食費(食料費,食費)の割合(パーセント単位)です。

消費支出 110,000円,飲食費 37,000円の人のエンゲル係数を求めるプログラム例。

本稿のように Jupyter Notebook 環境では,セル内で Enter キー(Return キー)を押すと改行され,最後の行を書いたあとに,Shift キーを押しながら Enter キー(または Return キー)を押して実行します。

In [5]:
cout << 37000 * 100. / 110000;
33.6364

割り算を先にしたり,100. の小数点をつけずに 100 として計算すると,不思議な答えが表示されますが,それについては後ほど解説します。

In [6]:
cout << 37000 / 110000 * 100.;
0
In [7]:
cout << 37000 * 100 / 110000;
33

ここからは,単に電卓的に使うだけではなく,応用・発展も見据えて以下のようなプログラム文を作成して実行することにします。

以下の例では,

  • 1行目で変数 s1 に消費支出である 110000(円)という数値を代入し,
  • 2行目で変数 s2 に飲食費である 37000(円)という数値を代入し,
  • 3行目でエンゲル係数を計算して,変数 x1 に代入し,
  • 4行目でエンゲル係数の値 x1 を表示させています。

変数 s1, s2int(整数), x1double(浮動小数点型の実数)としています。小数点以下の部分を持つ実数を表す浮動小数点型は,float, double, long double の3種類がありますが,この Notebook では詳細は省き,double で統一して説明します。

In [8]:
int s1 = 110000;
int s2 = 37000;
double x1 = s2 * 100. / s1;
cout << x1;
33.6364

エラーとデバグ

意に反して,プログラムがうまく動作しない場合があります。たとえば,上記の 3行目を以下のように書いた場合。

掛け算を示す演算子は *,割り算を示す演算子は / であるところを誤って,×÷ と書くと,これらの記号は Python では演算子として定義されていないのでエラーとなります。Jupyter Notebook では,以下のように誤りやその箇所を指摘してくれます。

In [9]:
int s1 = 110000;
int s2 = 37000;
double x1 = s2 × 100. ÷ s1;
cout << x1;
input_line_20:4:16: error: non-ASCII characters are not allowed outside of literals and identifiers
double x1 = s2 × 100. ÷ s1;
               ^~
input_line_20:4:15: error: expected ';' at end of declaration
double x1 = s2 × 100. ÷ s1;
              ^
              ;
input_line_20:4:24: error: non-ASCII characters are not allowed outside of literals and identifiers
double x1 = s2 × 100. ÷ s1;
                      ^~
Interpreter Error: 

別の種類の誤りもあります。たとえば,3行目の「100.」(パーセントで表すときは 100 をかけるのでした)を「1000.」と入力した場合...

In [10]:
int s1 = 110000;
int s2 = 37000;
double x1 = s2 * 1000. / s1;
cout << x1;
336.364

上記の例では Error の警告が出ませんが,答えは明らかに変です。(エンゲル係数の最大値は100だから。)

このような場合はコンピュータにとって誤りではなく,指示通りに計算し,その結果を表示します。 このようなプログラム作成者の不注意や勘違いによって生じるエラーには注意が必要です。

プログラムが正しく動作しない場合は,誤りの箇所を探し,修正して再度動作を確認します。正しく動作するようになるまで,プログラムを修正し,実行(Jupyter Notebook 環境では Shift + Enter)します。この作業をデバグといいます。

データの型と変数

上記の例の 1行目では,s1 という名前の変数に 100000 という数値を代入しています。変数名はアルファベットで始まる英数字列にします。大文字と小文字は区別されます。

小数点以下を含まない場合には整数型 int です。 3行目の最後,"\n" は改行を表します。4行目のように,endl としてもよいようです。(厳密には "\n"endl は違うようですが。)

In [11]:
int s1 = 100000;
int S1 = 40000;
cout << S1 << "\n";
cout << s1 << endl;
40000
100000

変数 ss に文字列を代入する場合は,以下のようにします。文字列を扱う型は,string です。利用時には最初に #include <string> としてやる必要があります。

In [12]:
#include <string>

string ss = "エンゲル係数";
cout << ss;
エンゲル係数

式と演算

掛け算を示す演算子は *,割り算を示す演算子は /。足し算は +,引き算は - です。

+ は文字列の連結演算にも使います。以下の例を参照。

In [13]:
string x0 = "エンゲル";
string y0 = "係数";
cout << x0 + y0;
エンゲル係数

文字列と数値を直接連結することはできません。

In [14]:
int s1 = 110000;
int s2 = 37000;
double x1 = s2*100./s1;
cout << "エンゲル係数は " + x1;
input_line_26:5:34: error: invalid operands to binary expression ('const char *' and 'double')
cout << "エンゲル係数は " + x1;
        ~~~~~~~~~~~~~~~~~ ^ ~~
Interpreter Error: 

そんなときは,数値を文字列に変換する関数 to_string() を使います。

In [15]:
int s1 = 110000;
int s2 = 37000;
double x1 = s2*100./s1;
cout << "エンゲル係数は " + to_string(x1);
エンゲル係数は 33.636364

cout のところは,わざわざ文字列に変換して連結しなくても,以下のようにも書くことができます。 cout 文は,<< によって複数の項目(変数)を連結して表示することができます。

In [16]:
int s1 = 110000;
int s2 = 37000;
double x1 = s2*100./s1;
cout << "エンゲル係数は " << x1 << " です。";
エンゲル係数は 33.6364 です。

主な演算子

加減乗除の演算子 +, -, *, /

優先的に計算したい箇所は丸括弧 ( )で グループ化します。

In [17]:
cout << 2 + (50 - 5 * 6)/4;
7

除算 / の例を以下に示します。

  • 1行目では,整数を整数で割るので,小数分を切り捨てた整数値を返します。

  • 2行目では,17. と最後に小数点をつけたので,double 型の値を返します。

In [18]:
cout << 17 / 3 << endl;
cout << 17./ 3 << endl;
5
5.66667

これで,最初のほうで述べた以下の表示の謎が解けましたね。

In [19]:
cout << 37000 * 100. / 110000;
33.6364
In [20]:
cout << 37000 / 110000 * 100.;
0
In [21]:
cout << 37000 * 100 / 110000;
33

べき乗(累乗)を表す演算子は C++ ではありません。$2^4$ の計算をするには,最初に

#include <cmath>

して pow() 関数を使います。引数には double 型の数値を入れます。

In [22]:
#include <cmath>

// macOS では,以下はエラーとなります。Ubuntu では無問題。
// cout << pow(2, 4);
// 以下は,macOS でも Ubuntu でも無問題。
cout << pow(2., 4.);
16

対話型プログラム

上記の例では,プログラムの中で消費支出や飲食費を決めていましたが,今度はプログラムを実行する人が入力できるようにしてみます。

以下のプログラム例では,cin >> s1 でキーボードからの入力値を変数 s1 に入れます。

In [23]:
int s1, s2; 
cout << "消費支出? ";
cin >> s1;
cout << "飲食費? ";
cin >> s2;

cout << "エンゲル係数は " << s2 * 100. / s1;
消費支出? 110000
飲食費? 37000
エンゲル係数は 33.6364

関数の定義と呼び出し

(これまでの例では1回しか計算していませんが)よく使う計算を「関数」として定義する例です。

以下の例では,エンゲル係数を計算する関数 calc() を定義しています。

// で始まる行はコメント行です。コメント行はそれを読む人間のための注釈であり,プログラムの実行時には無視されます。

In [24]:
double calc(int s1, int s2) {
// ここはコメント行。s1 は消費支出,s2 は飲食費,エンゲル係数を返す。
    return s2 * 100. / s1;
}

以下では,3行目で calc() を呼び出しています。

In [25]:
int s1 = 110000;
int s2 = 37000;
double x1 = calc(s1, s2);
cout << "エンゲル係数は " << x1;
エンゲル係数は 33.6364

いったん定義された関数は,以下のように何度でも使用できます。

In [26]:
cout << calc(120000, 43000);
35.8333

(練習)

消費支出を入力すると,エンゲル係数が 20 ~ 40 となる飲食費を表示するプログラムをつくりなさい。

組み込み関数を使う

関数は上記の例のように自分で定義することもできますが,あらかじめ用意されている「組み込み関数」を使うこともできます。

以下では,組み込み関数の例として,

  • 小数点以下を切り捨てる floor()
  • 小数点以下を四捨五入する round()

を使用しています。

  • ちなみに,小数点以下を切り上げる関数は ceil() です。
In [27]:
int s1 = 130000;
int s2 = 53000;
double x1 = calc(s1, s2);
cout << "エンゲル係数は " << x1;
cout << ":  floor(x1) = " << floor(x1);
cout << ":  round(x1) = " << round(x1) << endl;
エンゲル係数は 40.7692:  floor(x1) = 40:  round(x1) = 41

(練習)

小数点以下を切り上げたエンゲル係数の値を表示させるように上記のプログラムを変更しなさい。

条件分岐

条件分岐とは,例えばエンゲル係数の値によって実行文を変えることです。例を示します。

以下では,何回かこのプログラムを実行させるので,呼び出しやすいように関数 engel() として定義してしまいます。値を返さない関数なので void 型の関数として定義します。

In [28]:
void engel()
{
int s1, s2;
cout << "消費支出? ";
cin >> s1;
cout << "飲食費? ";
cin >> s2;
double x1 = calc(s1, s2);

if (x1 >= 80)
    cout << "エンゲル係数は " << x1 << " です。飲食費を使いすぎです。";
else
    cout << "エンゲル係数は " << x1 << " です。";
}

定義した関数 engel() の使い方は以下のようにします。

In [29]:
engel()
消費支出? 82000
飲食費? 71000
エンゲル係数は 86.5854 です。飲食費を使いすぎです。
In [30]:
engel()
消費支出? 80000
飲食費? 27000
エンゲル係数は 33.75 です。

条件分岐の if 文の書式は以下のようになっています。

if (条件式1) 
    条件式1 が満たされた場合に実行する文;
else if (条件式2) 
    条件式2 が満たされた場合に実行する文;
else
    それ以外の場合に実行する文;

(練習)

上記の条件分岐を,エンゲル係数が

  1. 80 以上の場合には「飲食費を使いすぎです。」
  2. 80 未満 40 以上の場合には「正常です。」
  3. 40 未満の場合には「もっと食べましょう。」

と表示させるように変更しなさい。

繰り返し処理

以下の例では,1行目で代入された消費支出に対してエンゲル係数を計算します。

1回だけ計算して表示するのではなく,2行目の飲食費の初期値(ここでは 40000 円)から,5行目の条件式(ここでは 80000 円以下)が成り立つ場合に,8行目にあるように 5000 円ずつ増やしながらエンゲル係数を表示します。

8行目の += は復号代入演算子と呼ばれるものの一つです。この場合の = は「等号」ではなく「代入」の意味で,右辺の値を新たに左辺の変数に代入する,という意味です。

s2 += 5000;

は以下と同等。

s2 = s2 + 5000;

また,プログラム文でよく見かける

i++

は,

i += 1

i = i + 1

と同じ意味です。

while 文による繰り返し

In [31]:
int s1 = 110000;
int s2 = 40000;
cout << "消費支出 " << s1 << " 円に対するエンゲル係数の値" << endl;

while (s2 <= 80000) {
    x1 = calc(s1, s2);
    cout << "  飲食費  " << s2 << " 円の場合: " << x1 << endl;
    s2 += 5000;
}
消費支出 110000 円に対するエンゲル係数の値
  飲食費  40000 円の場合: 36.3636
  飲食費  45000 円の場合: 40.9091
  飲食費  50000 円の場合: 45.4545
  飲食費  55000 円の場合: 50
  飲食費  60000 円の場合: 54.5455
  飲食費  65000 円の場合: 59.0909
  飲食費  70000 円の場合: 63.6364
  飲食費  75000 円の場合: 68.1818
  飲食費  80000 円の場合: 72.7273

while 文の書式は以下のとおりです。

while (条件式) {
    条件式が成り立つ場合に実行される文
}

for 文による繰り返し

In [32]:
int s1 = 110000;
cout << "消費支出 " << s1 << " 円に対するエンゲル係数の値" << endl;

for (int s2 = 40000; s2 <= 80000; s2 += 5000) {
    x1 = calc(s1, s2);
    cout << "  飲食費  " << s2 << " 円の場合: " << x1 << endl;    
}
消費支出 110000 円に対するエンゲル係数の値
  飲食費  40000 円の場合: 36.3636
  飲食費  45000 円の場合: 40.9091
  飲食費  50000 円の場合: 45.4545
  飲食費  55000 円の場合: 50
  飲食費  60000 円の場合: 54.5455
  飲食費  65000 円の場合: 59.0909
  飲食費  70000 円の場合: 63.6364
  飲食費  75000 円の場合: 68.1818
  飲食費  80000 円の場合: 72.7273

for 文の書式は以下のとおりです。

for (int ivar = istart; 条件式; ivar の増減式) {
    整数変数 ivar  istart から条件式が成り立つ間,実行される文;
    実行後は ivar の増減式により ivar の値が変化し,
    条件式が成り立つ間,繰り返される。
}

(練習)

以下の値を求めるプログラムを作成せよ。

$$\sum_{n = 1}^{10} n^2$$