計算数学演習第2回

変数について

今日は以下の内容で演習を行います.

  • 変数
  • C言語における変数の宣言と変数の使用
  • printf 関数を使って変数の内容を画面に表示する

前回のおさらい

  • Cのプログラムには main 関数が必要である
  • 関数の有効範囲は { から } までである
  • printf は画面に文字列を表示するための標準関数である
  • \n は改行(復改)を意味する
  • プログラムの先頭には「#include <stdio.h>」を必ず書く
  • 文末にはセミコロン ; が必要である
  • C言語の文法に従わないプログラムはコンパイル時にエラーとなる
  • プログラムの書き方のルールと慣習

プログラムの書き方のルールと慣習

C言語は今見たように言語としての文法があり,それに反するとコンピュータは機械語に翻訳できなくなってしまいます。
この文法に加えて書き方のルールがいくつかあります。

一つ目がトークンです。文法に対する自然言語で言うところの単語です。
コンピュータはこのトークンを一つ一つ読み取り,文法に則って機械語に翻訳してくれます。
なので,一つ一つが読み取れる形式で書かねばなりません
どうすればいいかというと,一つのトークンはつないで書いて,トークン同士は「スペース」「改行」「;」「()」「{}」で区切ることでコンピュータに独立したトークンとして読み込ませることができます。

たとえば,最も短いプログラムは,

int
main
(
)
{
return
0
;
}

とできますが,

int
main
(
)
{
ret
urn
0
;
}

 

とすると,returnが一つのトークンとして認められなくなってしまいます。

C言語は,フリーフォーマット・自由形式となっていて,基本的に自由に書いていけますが,このトークンが識別できるようになっていることが唯一無二の条件になります。
最も短いプログラムは,

int main(){return 0;}

のように1行にもできます。
しかし,先ほどのreturnが分解されてしまったのとは逆に,

intmain(){return0;}

としてすべてつなげてしまうと,intもmainもreturnも0も識別できなくなってしまいます。
記号として「;」「()」「{}」がつなげても大丈夫なのは,1文字で機能を果たしていて識別できるからです。
intmainはintmとainなどの適当な分割で意味がわからなくなってしまいます。

次に書き方の慣習についてです.
ここで書くことは絶対ではありませんが,皆さんが勉強する本やホームページでもだいたいはこの慣習に従っています。

先に何もしないプログラムを1行に書きましたが,このやり方ではプログラムが長くなれば非常に読みにくくなります。
Hello!を各プログラムは

#include <stdio.h>
int main(){printf("Hello!\n");return 0;}

というようにできますが,とても読みやすいとはいえません。
ですので元のプログラムにあるように,

#include <stdio.h>

int main()
{
printf("Hello!\n");
return 0;
}

と{}で一つの塊にすることが一般的なルールです。
こうすることでmain関数がどこからどこまでかが,わかりやすくなります。
また,printfが{}から右にずれていますが,インデントと呼ばれる書き方で,これをすることで階層構造を表します。

#include <stdio.h>

int main()
{
    printf("Hello!\n");

    return 0;
}

 

上のプログラムでも{}で分かれていますが,視覚的にわかりにくいと思います。
どちらかというと一塊を視覚的に見やすくするのはインデントによるところが大きく,同じ階層は同じインデントの深さにあることが求められます。

最後にコメントについてです。
短いプログラムは読めばわかりますが,長いプログラムになると何をしているのか読み込むことが大変になります。
ソースコードにはコンパイルされるプログラム以外のことを人間が読むことを目的として書き込む機能がコメントです。

#include <stdio.h>
/* ここもコメントです */
int main()
{
    /* コメントです */
    printf("Hello!\n"); /* ここもコメントです */
    // こんな書き方もあります。
    return 0;
}
/* ここもコメントです */

プログラムにはわかりやすくなるように何をしているか買い込む癖をつけておくことをお勧めします。
他の人に読んでもらって何をしているのかわかってもらえるようにするのがベストです。
なぜなら,明日のあなたは他人です。

このような短いプログラムではあまりコメントのありがたみは分かりませんが,より長いプログラムでは大変効果的です.プログラムのこの部分ではどのような処理をしているかといった内容をコメントとして書き入れる癖をつけておきましょう.

 

/* サンプルプログラム hello.c */
/*      b000000(学籍番号) 情報活用演習  */

#include <stdio.h>

/* main 関数 */
int main()
{
    /* Hello! と画面に表示する */
    printf("Hello!\n");

    return 0;
}

注意: 全角と半角に気をつけてください.日本語が打てる状態で * や / を書くと全角文字になってしまう場合があります.空白文字も同様に全角の空白文字となってしまうことがあります.こまめに日本語モードと英数モードを切り 替えてください.このようなミスもコンパイル時にエラーとなります.例えば * / a B は半角文字ですが,* / a B は全角文字です.つづりも文法もあっているのにエラーが出る場合,まずは全角文字を使っていないか疑いましょう.

今日の目標

プログラミング言語には必ず存在する”変数”を理解し使えるようになってもらいます.具体的には,以下のような内容をしっかり身に付けてください.

  • 変数の宣言
  • 変数への数値の代入
  • 変数内の数値を画面に表示(printf 関数)
  • 変数内に数値をキーボードを使って入力(scanf 関数

(今日はここから)

変数

全てのプログラミング言語には変数と呼ばれるものがあります.
変数は,データ(数値であったり,文字列であったり)を一時的に保存しておく箱によく例えられます.
変数にデータを入れることを代入と呼びます.
コンピュータープログラムは,そのような変数と呼ばれる箱に入ったデータを処理することにより,有用な仕事をします.

変数には,整数型実数型文字型と数種類ありますが,まずは整数型変数を扱います.
整数型変数は,整数値を保存するための箱です(実数値は保存できない)

変数にはそれぞれ符号付型(signed)と符号無し型(unsigned)の二種類がありますが,当面符号付型を用います(負の数も扱いたいので).

変数の宣言と代入

C言語では,変数を使う場合には関数のはじめの部分で全て宣言しておく必要があります.
次に「変数aに次々と値を代入する」簡単なサンプルソースプログラムを示します.
ファイル名を variables01.c として suugaku2017 フォルダーに保存して、コンパイル、実行してみてください.
(説明の為に行番号をつけています.エディターにて打ち込む時には行番号は打ち込まないでくだ さい.)

変数は代入が行われる度に、値が更新されます。(前の値の情報はどこにも残らない)

#include <stdio.h>

int main()
{
    int  a ;

    a = 7;
    printf("a is %d \n", a);
    a = 9;
    printf("a is %d \n", a);
    a = 10+20+30;
    printf("a is %d \n", a);

    return 0;
}

ちなみに、コンパイル、実行の仕方は、

gcc  variables01.c  -o  variables01

./variables01

です.

以下プログラムの説明です。

5行目:
これはこれから main 関数の中で使う変数を宣言している部分です.
intはIntegerの略で,整数型の変数を宣言する場合に使います.
その int のあとに a, b, c と列挙されていますが,このようにカンマで区切って列挙することで,一度に整数型変数 a, b を宣言することができます.
行の最後のセミコロンは文の終わりを示しています.
宣言とは,先ほどの変数は箱だという説明に沿って考えると,整数を入れることができる a, b とそれぞれ名前のついた2つの箱を用意したことになります.

7行目:
整数型変数 a に整数の値 7 を代入しています.

8,10,12行目:
(それぞれの時点での)整数型変数 a の内容を printf 関数を用いて画面に表示します.

9行目:
整数型変数 a に整数の値 9 を代入しています.

11行目:
整数型変数 a に10+20+30を演算した結果の値(整数)を代入しています.

変数の代入とは(a=bとb=aの違い)

C言語において”=”は代入を意味し、数学の等式を意味するわけではありません。
a=bとb=aでは全く意味が異なります。

例えば、”a=b; b=a+1;”という連立方程式を満たすa,bは存在しませんが、
プログラム上では”aにbの値を代入し、bには「aの値+1」の値を代入する”という意味になります。

プログラムvariable02.c として,コメントをいれて書き直したものを次に示します.
ここでの目標は,整数型変数の内容を画面に表示する場合のprintf 関数の使い方をマスターすることです.

#include <stdio.h>

int main()
{
    /* 整数型の変数 a, b, c を用意する */
    int  a, b, c;

    /* 整数型変数 b に値 12 を代入 */
    b = 12;
    /* 整数型変数 a にbの値 を代入 */
    a = b;
    /* 整数型変数 b にa+1の結果を代入 */
    b = a + 1;
    printf("a = %d, b= %d\n", a, b);
    /* 整数型変数 c に a+b の結果を代入 */
    c = a + b;

    /* 変数 c の内容を画面に表示 */
    printf("c = %d\n", c);
}

 

最初の変数の宣言の場所で,
int のあとに a, b, c と列挙されていますが,このようにカンマで区切って列挙することで,一度に整数型変数 a, b を宣言することができます.

二つの変数(整数)を画面に表示するにはこの例のように

printf(“a = %d, b = %d\n”, a, b);

などと書きます.最初の%dの部分がaの値に、二つ目の%dの部分がbの値に置き換わり,画面に文字列として表示されます。
三つの数値を表示したい場合は,同様に次のように書きます.

printf(“%d %d %d\n”, a, b, c);

この場合,%d が3つ並んでいますが,これらはそれぞれ後に続く a, b, c に対応しています.

つまり,代入とは “変数 = …”の形で書かれねばならず,

1: “=”の右側の数式中の変数を全てその値に置き換えて,演算を行う.

2: 上の演算結果を”=”の左側の変数に代入する.
ということを行っている.

今後この演習では、以下の変換文字列がよく使われます.

%d 10進数で出力する
%f %lf 浮動小数点数として出力する (%lf は倍精度浮動小数点)

このような変換文字列を,変数の型や表示したい様式にあわせて使うことになります.

言葉で説明するとごちゃごちゃしてわかりにくいですが,あれこれ自分で試してみるのが一番良いと思います.次の課題に取り組んでください.

課題1

例題プログラム variable02.c を変更して,整数型変数の加算以外の演算を試してください
(整数型変数とprintf関数の使い方に慣れてください.).
C言語では + の他に

+ 加算
減算
* 乗算
/ 除算
% 剰余  (整数のみ)

が利用できます.

注意:除算「/」について
C言語では,=が代入の意味であったように,数学での表記と同じでも対応しないのが「/」です。
int型(整数)同士で割り算をして,結果を見てください。

課題2

avariable02.cで,”b = 12;”の行を消すと,プログラムとしてどのような不都合が起こるか?考えてみよ.

実数型変数

実数型変数は

float  u, v, w;

または、

double u, v, w;

というように宣言します.float は,浮動小数点数の(floating point number)からきています.
また,doubleはfloatより精度が高い実数を表すことができ倍精度浮動小数点と呼ばれている.
printf 関数で実数型変数を表示する場合の変換文字列は %f です.
以下のプログラムをエディターで打ち込み実行してください.
ファイル名は variable03.c としてください.

#include <stdio.h>

int main()
{
    double x, y, s;
    x = 1.7;
    y = 3.0;

    s = x*y;

    printf("%lfと%lfの積は%lf です.\n", x,y,s);

    return 0;
}

(日本語の%と英数字の%は別物です。気をつけてください。)

注意 1: 実数型変数に値を入れる場合、r = 2.0 のように、少数点つきで値を与えるようにします。(逆に整数型変数に値を入れる場合、n = 2 のように、整数で与えます。)

注意 2: C 言語の実数型(浮動小数点数型)には float (単精度浮動小数点数型)のほかに double (倍精度浮動小数点数型)があります.
名前からわかるように,倍精度浮動小数点数型の方が,より高精度に数値を表現することができます(通常単精度浮動小 数点型は32bitであって,倍精度浮動小数点型は64bitで表現される).

課題3

半径 1.5 の円の面積(の近似値)を出力するプログラムvariable04.cを作成せよ.

ただし,半径はr,面積はsとして,それぞれdoubleで宣言すること.

実数型変数を使うことで,円の面積(の近似値)を求めることができました.
しかし,これでは違う半径の円の面積を求めたい場合,課題3のようにいちいちエディターでソースプログラムファイルを変更して,コンパイルし実行せねばなりません.
半径はキーボードで我々が入力したいものです.
次節では,標準関数である scanf 関数を使って,キーボードからの数値データの入力を実現します.

scanf 関数

キーボードから数値データを入力するには scanf 関数という標準関数を用います.
printf 関数は出力を行う関数でしたが,scanf 関数は入力を行う関数です.

scanf 関数による整数値の入力

scanf 関数を用いたもっとも簡単なプログラムは次のようなものになります.
ファイル名を input01.c として,エディターで打ち込んでください.

#include <stdio.h>

int main()
{
    int i;

    scanf("%d", &i);
    printf("%d\n", i);

    return 0;
}

 

このプログラムは,キーボードから入力された整数値データをそのまま画面に表示します.
(コンパイルして実行したあと、整数値を打ち込んでEnterを押すと、その数値が表示されます。)
このプログラムの中で,7行目の scanf 関数がキーボードからのデータ入力を行います.

scanf(“%d”, &i);

となっていますが,前半のダブルクォーテーションで囲まれた文字列は,printf 関数と同様の変換文字列です.
ただし,printf 関数のように通常の文字列と変換文字列が両方書くことはできず,scanf 関数では変換文字列のみ書くことができます
このサンプルプログラムでは,整数型変数 i に値を入力するので,整数型変数の変換文字列である %d がかかれています.
そのあとにはコンマ(,)に続いて &i とかかれています.
scanf 関数では,変換文字列に続いて,入力されたデータを格納する変数名がきますが,変数名の頭に & をつける必要があります.
& をつけねばならない理由はもちろんあるのですが,ここでは scanf 関数では変数の頭に必ず & をつけると覚えてください.

scanf 関数による実数値の入力

scanf 関数を用いて,実数値を入力し,それをそのまま出力するサンプルプログラムは次のようになります.ファイル名を input01b.c としてください(input01.c とほとんど同じなので,input01.c を変更し,別名保存しましょう).

#include <stdio.h>

int main()
{
    double a;

    scanf("%lf", &a);
    printf("%lf\n", a);

    return 0;
}

入力促進メッセージの出力

先の2つのプログラムでは,「・・を入力してください」といったメッセージは全く画面にでませんでした.これでは,プログラムを使う人にはあまりに不親切です.次のように input01.c を次のように変更しましょう.

#include <stdio.h>

int main()
{
    double a;

    printf("実数値を入力してください: ");
    scanf("%lf", &a);
    printf("入力された実数値は %lf です.\n", a);

    return 0;
}

7行目に printf 文が加わりました(9行目も変更されています).
このように,入力促進メッセージは,scanf 関数に先立って printf 関数で表示する必要があります.
次のように書きたくなる人もいるかもしれませんが,このような書き方はできません

間違った例

scanf(“実数値を入力してください: %lf”, &a);

円の面積を求めるプログラム(改良版)

では,scanf 関数を使って,先にでてきた円の面積を求めるプログラムを改良しましょう.

次のサンプルプログラムを input02.c としてエディターで打ち込んでください(行番号は無視してください).これまでの知識で十分理解できるはずです.

#include <stdio.h>

int main()
{
    double pi, r, s;

    pi = 3.14159;

    printf("円の半径(実数)を入力してください:");
    scanf("%lf", &r);

    s = pi*r*r;

    printf("円の面積は %lf です.\n", s);

    return 0;
}

このサンプルプログラムは,先ほどのサンプルプログラムvariable04.c を少しだけ変更した内容となっています.
先のプログラムで ,

r = 2.0;

としていた部分が,printf 関数と scanf 関数に置き換わっています.
ターミナルでコンパイルし,実行すると,

円の半径を入力してください:

と表示され,その状態でとまります.
そこで,メッセージどおりに,面積を求めたい円の半径を入力します.
例えば, 3.2 と打ち込んで,Enter キーをおしてみましょう.
半径 3.2 の円の面積が求まったでしょうか?

この節でわかったことをまとめると,

printf 関数と scanf 関数を組み合わせて用いれば,メッセージを表示して,
キーボードから数値を変数に読み込むことができる

ということになります.

処理が実行される順番.

プ ログラム中の処理の数少しづつが増えてきました。(変数の宣言、入力、演算、出力。。。。)
ここまでの作業でもう気づいていると思われますが、コンピュー ターがプログラムを実行する場合、プログラムに書かれている順序で処理が行われます。
ですので、処理の配置を適切に行わないと、当然正しく動きませんの で、ご注意ください。
(例えば先ほどの input02.c でprintf() と scanf() の順序を変えたりしてもらうと、分かると思います。)

きれいにプログラムを書く:スペースを上手に使う

さて,これまでに一通りの変数の使い方と式の書き方を学んできました.
今回,最初に復習したようにプログラムの書き方には慣習があります。
慣習は,ただなんとなくというより,ミス(バグ)を減らすための知恵でもあります。
見やすい=理解しやすい=ミスが少ないプログラムとなります。
特に,スペースをうまく使うと可読性が格段に上がります。
例えば,今回の内容で言えば,

#include <stdio.h>

int main()
{
    double pi, r, s;

    pi = 3.14159;

    printf("円の半径(実数)を入力してください:");
    scanf("%lf", &r);

    s = pi*r*r;
    // s=pi*r*r;

    printf("円の面積は %lf です.\n", s);

    return 0;
}

12行目の部分を13行目のように,=の前後にスペースを入れずに書いても問題はありませんが,スペースを入れることをお勧めします。
これくらい短い式だと恩恵を感じませんが,複雑で長い式の場合には重要になります。

#include <math.c>

int main()
{
    double s, a, b, c;
    a = 1.0;
    b = 3.0;
    c = 10.0;

    s = (-b+sqrt(b*b-4.0*a*c))/(4*a);
    // s=(-b+sqrt(b*b-4.0*a*c))/(4*a);
    // s = ( -b + sqrt( b*b - 4.0*a*c ) ) / ( 2*a );

    return 0;
}

2次方程式の解の公式くらいでもなかなか見にくくなります。
スペースを上手に使って見やすい=理解しやすいプログラムをかけるようになりましょう。
また計算式を書く場合には,括弧()の使い方も重要になります。
数学では中括弧や大括弧など形を変えられますが,C言語では()以外使えないので,入れ子構造が増えると必要な数の括弧があるのかわかりにくくなります。
12行目のように括弧の前後にスペースを入れるのも効果的です。
(ただし,式が横に長くなるので,入れすぎると見にくくなります。うまく調整してください)

これまでの内容の復習として次の課題に取り組んでください.

課題5

整数n,mを入力すると、nをmで割った余りを表示するプログラムを作成せよ.(ヒント:n%mを使う。)

課題6

    \[x_{n+1} = 1.5 x_n +1\]

という漸化式が成り立つとする.実数x_0を入力すると、x_1, x_2, x_3を出力するプログラムを作成せよ.

以下の課題は少し難易度が高いかもしれませんが,(if文,for文,while文を使わずに)挑戦してみてください.
ちなみに「n桁以下の自然数を入力したら」という課題は,n+1桁以上の数字を入力したときの出力はどうであっても良いとします.
(ヒント:整数同士の演算” / “や” % “の意味をよく把握していれば解けるはずです.)

課題7

課題6を一つの変数を宣言するだけで作成せよ.

課題8

三桁の自然数を入力したら,100の位の数字を出力するプログラムを作成せよ

課題9

五桁以下の自然数を入力したら,全ての桁の数字を足した数字を出力するプログラムを作成せよ

課題10

五桁以下の自然数を入力したら,下三桁の数字を出力するプログラムを作成せよ

課題11

三桁以下の(10進数の)自然数を入力したら,その数を二進数で表示するプログラムを作成せよ.
例: 三桁以下の自然数を入力してください:231 二進数であらわすと11100111です.

今日学んだ事

  • 変数(整数型と実数型)を使えるようになりました
  • 変数を使った足し算を行いました
  • 変数を使ったいろいろな計算をしました
  • 変数の内容を printf 関数を用いて画面に表示できるようになりました
  • scanf 関数を使って,数値データをキーボードから入力できるようになりました
  • scanf 関数では,変数名の頭に & をつける必要がありました