この Notebook は,
テキスト「オープンソースソフトウェアによる情報リテラシー −第2版−」の
のプログラミング部分に相当する内容を C kernel for Jupyter という Juypter kernel を利用して書いてみたものです。
エンゲル係数とは,家計の消費支出に占める飲食費(食料費,食費)の割合(パーセント単位)です。
消費支出 110,000円,飲食費 37,000円の人のエンゲル係数を求めるプログラム例。
本稿のように Jupyter Notebook 環境では,セル内で Enter キー(Return キー)を押すと改行され,最後の行を書いたあとに,Shift キーを押しながら Enter キー(Return キー)を押して実行します。
#include <stdio.h>
と書く,とまずは覚えましょう。main()
関数が必要です。とりあえず int main(void)
と書く,と覚えましょう。{
と 7行目の }
で囲まれた部分が main()
関数の内容です。"%f"
つまり浮動小数点数で表示し,"\n"
つまり改行する,という内容です。文の最後には,セミコロン ;
を忘れずにつけます。return 0;
は,int main()
関数の定義の最後につける,と覚えておきます。#include <stdio.h>
int main(void)
{
printf("%f\n", 37000 * 100. / 110000);
return 0;
}
割り算を先にしたりして計算すると不思議な答えが表示されたりしますが,それについては後ほど解説します。
#include <stdio.h>
int main(void)
{
printf("%f\n", 37000 * 100. / 110000);
printf("%f\n", 37000 / 110000 * 100. );
return 0;
}
ここからは,単に電卓的に使うだけではなく,応用・発展も見据えて以下のようなプログラム文を作成して実行することにします。
以下の例では,
s1
に消費支出である 110000
(円)という数値を代入し,s2
に飲食費である 37000
(円)という数値を代入し,x1
に代入し,x1
を表示させています。変数 s1
, s2
は int
(整数), x1
は double
(浮動小数点型の実数)としています。
#include <stdio.h>
int main(void)
{
int s1 = 110000;
int s2 = 37000;
double x1 = s2 * 100. / s1;
printf("%f\n", x1);
return 0;
}
意に反して,プログラムがうまく動作しない場合があります。たとえば,上記の 3行目を以下のように書いた場合。
掛け算を示す演算子は *
,割り算を示す演算子は /
であるところを誤って,×
や ÷
と書くと,これらの記号は Python では演算子として定義されていないのでエラーとなります。Jupyter Notebook では,以下のように誤りやその箇所を指摘してくれます。
#include <stdio.h>
int main(void)
{
int s1 = 110000;
int s2 = 37000;
double x1 = s2 × 100. ÷ s1;
printf("%f\n", x1);
return 0;
}
別の種類の誤りもあります。たとえば,7 行目の「100.」(パーセントで表すときは 100 をかけるのでした)を「1000.」と入力した場合...
#include <stdio.h>
int main(void)
{
int s1 = 110000;
int s2 = 37000;
double x1 = s2 * 1000. / s1;
printf("%f\n", x1);
return 0;
}
上記の例ではエラーが出ませんが,答えは明らかに変です。(エンゲル係数の最大値は100だから。)
このような場合はコンピュータにとって誤りではなく,指示通りに計算し,その結果を表示します。 このようなプログラム作成者の不注意や勘違いによって生じるエラーには注意が必要です。
プログラムが正しく動作しない場合は,誤りの箇所を探し,修正して再度動作を確認します。正しく動作するようになるまで,プログラムを修正し,実行(Jupyter Notebook 環境では Shift + Enter)します。この作業をデバグといいます。
なお,Jupyter Notebook の Fortran kernel では,バグのためか,1回 Shift キーを押しながら Enter キーを押しても実行結果が表示されない場合があります。そんなときは,同じセルを選択し,もう一度,Shift + Enter してみてください。
上記の例の 5 行目では,s1
という名前の変数に 1100000
という数値を代入しています。変数名はアルファベットで始まる英数字列にします。大文字と小文字は区別されます。以下のプログラム例を参照。
#include <stdio.h>
int main(void)
{
int s1 = 110000;
int S1 = 37000;
printf("%d\n", S1);
printf("%d\n", s1);
return 0;
}
変数 ss
に文字列を代入する場合は,以下のようにします。文字列を扱う型は,char
です。
ここでは,char ss[80]
として最大80文字格納できる変数 ss
を宣言し,文字列 エンゲル係数
を代入しています。
6 行目の puts()
関数は文字列を出力します。printf()
関数と違い,書式を設定する必要がありませんし,出力後,自動的に改行します。
printf()
関数を使って文字列を出力する場合は,7 行目のように "%s\n"
と指定して文字列変数 ss
(と改行 \n
)を出力します。
#include <stdio.h>
int main(void)
{
char ss[80] = "エンゲル係数";
puts(ss);
printf("%s\n", ss);
return 0;
}
掛け算を示す演算子は *
,割り算を示す演算子は /
。足し算は +
,引き算は -
です。
文字列の連結演算は +
ではなく,strcat()
関数を使います。strcat()
関数をはじめとした文字列処理関数を使うときは,
#include <string.h>
が必要です。 以下の例を参照。
#include <stdio.h>
#include <string.h>
int main(void)
{
char x0[80] = "エンゲル";
char y0[80] = "係数";
puts(strcat(x0, y0));
return 0;
}
文字列と数値を直接連結することはできません。
そんなときは,数値を文字列に変換する関数... なんてことを考えずに,printf()
関数で以下のように書きます。
%s
は文字列としての出力,%f
は浮動小数点数としての出力の指定です。
#include <stdio.h>
#include <string.h>
int main(void)
{
char ss[80] = "エンゲル係数は ";
int s1 = 110000;
int s2 = 37000;
double x1 = s2 * 100. / s1;
printf("%s%f\n", ss, x1);
return 0;
}
#include <stdio.h>
int main(void)
{
int x = 2 + (50 - 5 * 6)/4;
printf("%d\n", x);
return 0;
}
除算 /
の例を以下に示します。
最初の出力では,整数を整数で割るので,小数分を切り捨てた整数値を返します。
次の出力では,17.
と最後に小数点をつけたので,double
型の値を返します。
#include <stdio.h>
int main(void)
{
printf("%d\n", 7/14);
printf("%f\n", 7./14);
return 0;
}
掛け算と割り算の順序を変えると,以下のように答えが変わってしまいますが,この理由もわかりますね?
#include <stdio.h>
int main(void)
{
printf("%d\n", 7 / 14 * 5);
printf("%d\n", 7 * 5 / 14);
return 0;
}
べき乗(累乗)を表す演算子は C ではありません。$2^4$ の計算をするには,最初に
#include <math.h>`
して pow()
関数を使います。
#include <stdio.h>
#include <math.h>
int main(void)
{
printf("%f\n", pow(2, 4));
return 0;
}
上記の例では,プログラムの中で消費支出や飲食費を決めていましたが,今度はプログラムを実行する人が入力できるようにしてみます。
以下のプログラム例では,scanf()
関数を使って,キーボードからの入力値を変数 s1
や s1
に整数として入れます。
scanf()
関数は入力値の格納先をアドレスで指定するので,
scanf("%d", s1);
ではなく,
scanf("%d", &s1);
のように,変数の前に &
をつけます。
//%cflags:-Wno-gnu-zero-variadic-macro-arguments
// macOS の場合は上記1行をつけないと警告が出る。
#include <stdio.h>
int main(void)
{
int s1, s2;
printf("消費支出? ");
scanf("%d", &s1);
printf("飲食費? ");
scanf("%d", &s2);
double x1 = s2 * 100. / s1;
printf("エンゲル係数は %f\n", x1);
return 0;
}
(これまでの例では1回しか計算していませんが)よく使う計算を「関数」として定義する例です。
以下の例では,エンゲル係数を計算する関数 calc()
を定義しています。
//
で始まる行はコメント行です。コメント行はそれを読む人間のための注釈であり,プログラムの実行時には無視されます。
//%cflags:-Wno-gnu-zero-variadic-macro-arguments
// macOS の場合は上記1行をつけないと警告が出る。
#include <stdio.h>
double calc(int s1, int s2) {
// ここはコメント行。s1 は消費支出,s2 は飲食費,エンゲル係数を返す。
return s2 * 100. / s1;
}
int main(void)
{
int s1 = 110000;
int s2 = 37000;
double x1 = calc(s1, s2);
printf("エンゲル係数は %f\n", x1);
return 0;
}
消費支出を入力すると,エンゲル係数が 20 ~ 40 となる飲食費を表示するプログラムをつくりなさい。
関数は上記の例のように自分で定義することもできますが,あらかじめ用意されている「組み込み関数」を使うこともできます。
以下では,組み込み関数の例として,
floor()
round()
を使用しています。
ceil()
です。これらの関数を使うときは,最初に
#include <math.h>
の記述が必要です。
#include <stdio.h>
#include <math.h>
double calc(int s1, int s2) {
// ここはコメント行。s1 は消費支出,s2 は飲食費,エンゲル係数を返す。
return s2 * 100. / s1;
}
int main(void)
{
int s1 = 110000;
int s2 = 37000;
double x1 = calc(s1, s2);
printf("エンゲル係数は %f\n", x1);
printf(" floor(x1) = %f\n", floor(x1));
printf(" round(x1) = %f\n", round(x1));
return 0;
}
小数点以下を切り上げたエンゲル係数の値を表示させるように上記のプログラムを変更しなさい。
条件分岐とは,例えばエンゲル係数の値によって実行文を変えることです。例を示します。
//%cflags:-Wno-gnu-zero-variadic-macro-arguments
// macOS の場合は上記1行をつけないと警告が出る。
#include <stdio.h>
double calc(int s1, int s2) {
// ここはコメント行。s1 は消費支出,s2 は飲食費,エンゲル係数を返す。
return s2 * 100. / s1;
}
int main(void)
{
int s1, s2;
printf("消費支出? ");
scanf("%d", &s1);
printf("飲食費? ");
scanf("%d", &s2);
double x1 = calc(s1, s2);
if (x1 >= 40){
printf("エンゲル係数は %f です。", x1);
printf("飲食費を使いすぎです。\n");
}
else
printf("エンゲル係数は %f です。", x1);
return 0;
}
条件分岐の if
文の書式は以下のようになっています。
if (条件式1) {
条件式1 が満たされた場合に実行する文;
}
else if (条件式2) {
条件式2 が満たされた場合に実行する文;
}
else {
それ以外の場合に実行する文;
}
上記の条件分岐を,エンゲル係数が
と表示させるように変更しなさい。
以下の例では,消費支出 s1
に対してエンゲル係数を計算します。
1回だけ計算して表示するのではなく,飲食費の初期値(ここでは 40000
円)から,条件式(ここでは 80000
円以下)が成り立つ場合に, 5000
円ずつ増やしながらエンゲル係数を表示します。
+=
は復号代入演算子と呼ばれるものの一つです。この場合の =
は「等号」ではなく「代入」の意味で,右辺の値を新たに左辺の変数に代入する,という意味です。
s2 += 5000;
は以下と同等。
s2 = s2 + 5000;
また,プログラム文でよく見かける
i++
は,
i += 1
や
i = i + 1
と同じ意味です。
while
文による繰り返し¶#include <stdio.h>
double calc(int s1, int s2) {
// ここはコメント行。s1 は消費支出,s2 は飲食費,エンゲル係数を返す。
return s2 * 100. / s1;
}
int main(void)
{
int s1 = 110000;
int s2 = 40000;
double x1;
printf("消費支出 %d 円に対するエンゲル係数の値\n", s1);
while (s2 <= 80000) {
x1 = calc(s1, s2);
printf(" 飲食費 %d 円の場合: %f\n", s2, x1);
s2 += 5000;
}
return 0;
}
while
文の書式は以下のとおりです。
while (条件式) {
条件式が成り立つ場合に実行される文;
}
for
文による繰り返し¶#include <stdio.h>
double calc(int s1, int s2) {
// ここはコメント行。s1 は消費支出,s2 は飲食費,エンゲル係数を返す。
return s2 * 100. / s1;
}
int main(void)
{
int s1 = 110000;
int s2 = 40000;
double x1;
printf("消費支出 %d 円に対するエンゲル係数の値\n", s1);
for (s2 = 40000; s2 <= 80000; s2 += 5000) {
x1 = calc(s1, s2);
printf(" 飲食費 %d 円の場合: %f\n", s2, x1);
}
return 0;
}
for
文の書式は以下のとおりです。
for (int ivar = istart; 条件式; ivar の増減式) {
整数変数 ivar が istart から条件式が成り立つ間,実行される文;
実行後は ivar の増減式により ivar の値が変化し,
条件式が成り立つ間,繰り返される。
}
以下の値を求めるプログラムを作成せよ。
$$\sum_{n = 1}^{10} n^2$$