CCCC プログラミング言語テキストweb.tuat.ac.jp/~ykuroda/tuatonly/C-programing...

81
C プログラミング言語テキスト プログラミング言語テキスト プログラミング言語テキスト プログラミング言語テキスト 第 1 章 プログラムの基礎 プログラムの基礎 プログラムの基礎 プログラムの基礎 ................................ ................................ ................................ ............................................ ............ ............ ............ 1 1.プログラムの基本形と画面への出力 ............................................................ 1 2. 入力のあるプログラム ................................................................................ 5 3. 判断と枝分かれ~IF 文~ ........................................................................... 9 4. 繰り返し FOR文~ ............................................................................. 14 5. DOWHILE....................................................................................... 20 6. WHILE................................................................................................ 23 7. 繰り返しのまとめ ..................................................................................... 25 第 2 章 応用 応用 応用 応用 ................................ ................................ ................................ ....................................................... ....................... ....................... ....................... 28 28 28 28 1.変数の型と書式の設定の仕方..................................................................... 28 2 ................................................................................................................ 34 3 文字と文字列・列とポインター.............................................................. 37 4.ファイル..................................................................................................... 43 第 3 章 関数 関数 関数 関数 ................................ ................................ ................................ ....................................................... ....................... ....................... ....................... 48 48 48 48 1.関数とは何か.............................................................................................. 48 2.関数を作る ................................................................................................. 55 3.再帰呼び出し.............................................................................................. 67

Transcript of CCCC プログラミング言語テキストweb.tuat.ac.jp/~ykuroda/tuatonly/C-programing...

  • CCCC プログラミング言語テキストプログラミング言語テキストプログラミング言語テキストプログラミング言語テキスト

    第第第第 1111 章章章章 プログラムの基礎プログラムの基礎プログラムの基礎プログラムの基礎 ................................................................................................................................................................................ 1111

    1.プログラムの基本形と画面への出力 ............................................................ 1

    2. 入力のあるプログラム ................................................................................ 5

    3. 判断と枝分かれ~IF 文~ ........................................................................... 9

    4. 繰り返し ~FOR文~ ............................................................................. 14

    5. DO~WHILE文 ....................................................................................... 20

    6. WHILE文 ................................................................................................ 23

    7. 繰り返しのまとめ ..................................................................................... 25

    第第第第 2222 章章章章 応用応用応用応用 ............................................................................................................................................................................................................................ 28282828

    1.変数の型と書式の設定の仕方 ..................................................................... 28

    2 列 ................................................................................................................ 34

    3 文字と文字列・配列とポインター .............................................................. 37

    4.ファイル ..................................................................................................... 43

    第第第第 3333 章章章章 関数関数関数関数 ............................................................................................................................................................................................................................ 48484848

    1.関数とは何か .............................................................................................. 48

    2.関数を作る ................................................................................................. 55

    3.再帰呼び出し .............................................................................................. 67

  • 平成 27 年 4 月 29 日(水)

    1

    第 1 章 プログラムの基礎

    1.プログラムの基本形と画面への出力

    最も簡単なプログラム

    1

    2

    3

    4

    5

    6

    【実行結果】

    【解説】1.C 言語のプログラムの書き方

    C 言語のプログラムには、必ず main 関数というものがあります。そして、

    { と } でくくられた部分に、文や関数名、変数名(詳細は追ってひとつひとつ

    説明していきます)を記述していきます。また、大文字と小文字は別の文字と

    して区別しています。

    但し、一部の市販の入門書では、main 関数の記述が例 1-1.1 のようになって

    いないで、以下のようになっていることがあります。

    これは C 言語が誕生した頃の仕様で、例 1-1.1 の書き方は米国規格協会で定め

    た(ANSI)に沿ったものです。詳細は後の章で述べます。本書では、例 1-1.1

    のような書き方で書いています。

    2.printf

    <表現> printf ( "文字列" )

    <意味> " と " で囲まれた文字列を出力します。この文字列を、書式制御文

    字列といいます。例題中で、¥n というのは、改行をする特殊記号です。

    /* My First Program */

    #include

    int main(void)

    {

    printf("hello!¥n");

    }

    hello!

    main ( )

    {

    ・・・;

    }

  • 平成 27 年 4 月 29 日(水)

    2

    3.注釈(コメント)

    例 1-1.1 の 1 行目のように、プログラム中に注釈を書くことが出来ます。

    /*と*/でくくります。

    4. #include <stdio.h>

    例 1-1.1 の 2 行目については、第 3 章で説明します。ここでは説明しません。

    Printf を使うときに使うおまじないと思って下さい。

    足し算をするプログラム

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    【実行結果】

    【解説】1.変数

    計算機で計算するには、値をしまっておく「箱」、すなわち値を記憶する場所

    を用意しなければなりません。その「箱」のことを変数といい、その名前を変

    数名といいます。

    例 1-1.2 では a や b、cが変数名です。

    2.型と宣言

    変数にはそれぞれ決められた型をもった値を入れることができます。型には

    int(整数型)、float(実数型=小数点付きと思って下さい)、char(文字型)などがあ

    ります。変数に対してその型を決めることを変数宣言するといい、それを行う

    文を宣言文といいます。

    例は、5 行目が宣言文になります。一般的な書き方は以下の通りです。

    /* My Second Program */

    #include

    int main(void)

    {

    int a,b,c;

    a=12;

    b=23;

    c=a+b;

    printf("%d¥n",c);

    }

    35

  • 平成 27 年 4 月 29 日(水)

    3

    3.値の代入

    a=12 や c=a+b というような書き方を代入といいます。

    右辺の値(計算結果)を左辺の変数にしまうことをします。

    4. 式の書き方

    以下の記号を使用して普通にそのまま式を書きます。但し、括弧は、( と ) し

    か使えません。

    意味 数学記号 C 言語の書き方

    加算 + +

    減算 - -

    乗算 × *

    除算 ÷ /

    余り ・・・ %

    <例>(a+b)×(c+d) → (a+b) * (c+d)

    上記の C 言語での記号を、算術演算子といいます。

    5. printf で整数型の値を出力する

    <表現> printf ( "%d¥n" , 整数型の変数名や定数 ) ;

    <意味> 変数型の値を出力します。出力すべき整数型の値と、 " と " の中

    の%d とが対応しています。¥n は、改行するための特殊記号です。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    【実行結果】

    型名 変数名, 変数名, ・・・, 変数名;

    /* 改行の練習 */

    #include

    int main(void)

    {

    int a;

    a=123;

    printf(" a= %d ¥n",a);

    printf(" a= %d ",a);

    printf(" a= %d ¥n",a);

    }

    a= 123

    a= 123 a= 123

  • 平成 27 年 4 月 29 日(水)

    4

    【解説】1.文字と数値を出力する

    <表現> printf ( "文字 %d" , 整数型の変数名や定数 ) ;

    <意味> 文字と数値を一緒に出力します。やはり、 " と " の中の %d は、出

    力すべき値(例題では a)が対応しています。¥n がなければ改行をしません。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    【実行結果】

    【練習問題 1.1】 今までに出てきた例題の文で¥n を入れたり取ったりして、両者の違い

    を実感してみよう。

    【練習問題 1.2】 以下の実行例のように、住所と名前を表示するプログラムを作ろう。

    【練習問題 1.3】 printf を使って、いろいろな記号や空白を文字列として、画面一面に模

    様か絵らしいものを書くプログラムを作ってみよう。(スクリーンは横 80

    ケタ、縦 24 行である)

    /* 変数宣言のあるプログラム例 */

    #include

    int main(void)

    {

    int tate,yoko,menseki;

    tate=5;

    yoko=10;

    menseki=tate*yoko;

    printf("menseki = %d¥n",menseki);

    }

    menseki = 50

    171

    東京都豊島区目白1-5-1

    学習院大学計算機センター

    入沢 寿美

  • 平成 27 年 4 月 29 日(水)

    5

    2. 入力のあるプログラム

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    【実行例】下線の部分を入力します。

    【解説】1.scanf で整数の値を読む

    <表現> scanf ( "%d" , &変数名 ) ;

    <意味> scanf は変数に値を読み込む命令です。これを実行するとキーボー

    ドから値が入力されるのを待ちます。変数に代入したい値を空白で区切りなが

    ら変数の数だけ入力してください。

    &の意味はここでは説明しませんが、おまじないと思って下さい。また、例題

    では、 " と " の中に二つの %d がありますが、始めのそれは変数 a に対応し

    ていて、後のは変数 b に対応しています。

    四則演算の結果(整数型)

    1

    2

    3

    4

    5

    6

    7

    /* 入力のあるプログラム */

    #include

    int main(void)

    {

    int a,b,c;

    printf("Please input two numbers :");

    scanf("%d %d",&a,&b);

    c=a+b;

    printf("%d¥n",c);

    }

    Please input two numbers > 100 200

    300

    //* 整数型の演算 */

    #include

    int main(void)

    {

    int a,b;

    printf("Enter two numbers:");

    scanf(" %d %d",&a,&b);

    printf(" 和 :%d¥n",a+b);

  • 平成 27 年 4 月 29 日(水)

    6

    8

    9

    10

    11

    12

    13

    【実行例】整数型の商が 2 になるところに注目してください。これは、1 未満の値が切り捨

    てられて整数型の値となるからです。

    四則演算の結果(実数型)

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    【実行結果】

    Enter tow numbers : 7 2

    和 :9

    差 :5

    積 :14

    商 :3

    余り :1

    /* 実数型の演算 */

    #include

    int main(void)

    {

    float a,b;

    printf("Enter two numbers:");

    scanf("%f %f",&a,&b);

    printf(" 和 :%f¥n",a+b);

    printf(" 差 :%f¥n",a-b);

    printf(" 積 :%f¥n",a*b);

    printf(" 商 :%f¥n",a/b);

    }

    Enter tow numbers : 7.0 2.0

    和 :9.000000

    差 :5.000000

    積 :14.000000

    商 :3.500000

    printf(" 差 :%d¥n",a-b);

    printf(" 積 :%d¥n",a*b);

    printf(" 商 :%d¥n",a/b);

    printf(" 余り :%d¥n",a%b);

    }

    注意:整数型のた

    め、「3.5」ではなく

    「3」と出力される

  • 平成 27 年 4 月 29 日(水)

    7

    【解説】1.実数型の値の入出力

    <表現> printf ( "%f¥n" , 変数名 ) ;

    scanf ( "%f¥n" , &変数名 ) ;

    <意味> float 型の入力と出力を取り扱うときには、 %f を用います。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    【実行結果】

    【練習問題 1.4】 次の結果を調べてみよう。

    1. 実数と整数の混合の四則結果

    2. 実数型の計算結果を整数型の変数に代入した結果

    1

    2

    3

    4

    5

    /* 代入の理解を深めるプログラム例 */

    #include

    int main(void)

    {

    int a,b;

    printf("a を入力して下さい ==> ");

    scanf("%d",&a);

    printf("a には%d が入っています¥n",a);

    b=a;

    printf("それを b に代入すると b も%d になります¥n",b);

    a+=1;

    printf("a に 1 を足したものを a に入れると a が%d になります¥n",a);

    }

    a を入力してください ==〉10

    a には 10 が入っています

    それを b に代入すると b も 10 になります

    a に 1 を足したものを a に入れると a が 11 になります

    /* 文字列の入力 */

    #include

    int main(void)

    {

    char name[20], univ[20];

    注意:これで、20文字まで読み込み

    可能

  • 平成 27 年 4 月 29 日(水)

    8

    6

    7

    8

    9

    10

    11

    12

    【実行結果】

    【解説】1.文字列の宣言

    詳しいことは第 2 章で説明しますが、名前などを表す文字列を変数として宣

    言するときには、6 行目のように、まず型名 char を書き、続いて変数名と文字

    数( [ ] で囲む)を書きます。Char A の場合、A は1文字のみから成る文字

    型変数です。

    2.文字列の入出力

    <表現> printf ( "%s¥n" , 変数名 ) ;

    scanf ( "%s" , 変数名 )

    <説明> 文字列を出力したり入力したりするときは、 %s を使います。ただし、

    scanf で入力するとき、整数型や実数型と異なり、&はつけないとこ

    ろに注意してください。

    【入出力の型指定】これまで printf や scanf で使ってきた%についてまとめておきます。

    printf や scanf の書式制御文字列の中身で、 %で始まる文字列は、それに対応する変数の

    書式制御に使用されます。 d や f、s は、変数の型を指定するもので、それぞれ上の表の通

    りの型を指定します。この他、「何桁で出力する」などの指定ができますが、それは第 2 章

    で説明します。

    %d

    %f

    %s

    10 進数整数の入出力

    実数型も入出力

    文字列の入出力

    あなたの名前は何ですか? 和花

    和花さんの大学はどこ? 学習院

    printf( "あなたの名前は何ですか ? " );

    scanf( "%s", name );

    printf( "%s さんの大学はどこ ? ", name );

    scanf( "%s", univ );

    }

  • 平成 27 年 4 月 29 日(水)

    9

    3. 判断と枝分かれ

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    【実行結果】入力する値によって結果が違うことに注意。

    【構文】if 文

    条件式を調べてそれが成り立つとき(真であるという)、文 1 を実行します。条

    件式が成り立たないとき(偽であるという)、文 2 を実行します。

    /* 7 月 31 日作成 */

    #include

    int main(void)

    {

    int temp;

    printf("今何度だい?");

    scanf("%d",&temp);

    if(temp>30)

    {

    printf("暑い!!何とかして!!¥n");

    }

    else

    {

    printf("夏にしては過ごしやすいな¥n");

    }

    }

    今何度?34

    暑い!!何とかして!!

    今何度?27

    夏にしては過ごしやすいね

    if (条件式)

    文 1 ;

    else

    文 2 ;

  • 平成 27 年 4 月 29 日(水)

    10

    else 及び文 2 は省略することができますが、そのときは、条件を満たさないと

    きには何も実行しないので次の行へと進みます。

    例 1-3.1 では、10 行目の temp>30 が条件式で、それを満たせば 11 行目を、

    満たさなければ 15 行目を実行します。

    【条件式の書き方】

    意味 数学記号 C 言語の書き方

    等しい

    より大きい

    より小さい

    等しいか、より大きい

    等しいか、より小さい

    等しくない

    ==

    >

    <

    >=

    =c

    複数の条件を表すとき、等式や不等式を、次のような論理記号(論理演算子と

    いう)で結んだものを使用します。

    名 前 C 言語の表現 意味

    論理積

    論理和

    否 定

    A && B

    A || B

    !A

    A、B が両方とも成立すれば真

    A、B どちらかが成立すれば真

    A が成立しなければ真となる

    if (条件式)

    文 1 ;

    NO YES

    文 2

    条件式

    文 1

    NO YES

    条件式

    文 1

  • 平成 27 年 4 月 29 日(水)

    11

    但し、A と B は各々条件式である

    (例) x + y == c && z > 0

    意味:「x+y==c」と「z>0」が両方成立すれば真となる。

    (注意)以下のように三つ以上の値(または式)を等式や不等式で結んだ形は使用でき

    ません。

    (例)誤った表記: 0 < x < 100 p == q == 1

    正しい表記: 0 < x && x > 100 p == 1 && q == 1

    ||よりも&&の方が評価の優先順位が高いです。また、同じ論理演算子では、左

    から順に評価していきます。優先順位に反して意図的に評価の順番を変えたいと

    きには、()でくくってやります。

    (例)a > b || b == c && c==d 「b==c && c ==d」を先に評価する。

    (a > b || b == c ) && c == d 「a > b || b == c」を先に評価する。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    /* 今何度? PART 2 */

    #include

    int main(void)

    {

    int temp;

    printf("今 何度 ? ");

    scanf("%d",&temp);

    if(temp

  • 平成 27 年 4 月 29 日(水)

    12

    21

    22

    23

    24

    25

    26

    【実行結果】

    【構文】if 文を何重にも入れ子にして使用することもできます。

    まず条件式 1 を評価して、満たせば文 1 を実行し、満たさなければ条件式 2 を

    評価します。最初と同様に、満たせば文 2 を実行、満たさなければ次の条件式の

    評価へと進みます。どの条件式も満たさなかった場合、else 以下の文を実行しま

    す。どの条件も満たさず、しかも else 以下が省略された場合、結果的に何も実行

    せずに if 文を終わります。

    条件により実行するものが複数ある場合には、例 1-3.2 の 11行目と 13行目の

    ように、 { と } でくくります。これを複文といいます。 ない

    【練習問題 1.5】 西暦を入力して、「1995 年は平成 7 年です」というように年号や年を出

    力するプログラムを作ってみよう。但し、各年号の境目は両方の年号を出

    今 何度 ? 36

    あはは...異常な暑さで声も出ないよ

    今 何度 ? 34

    暑い!!計算機センターに行って涼まないといられない

    if (条件式 1)

    文 1 ;

    else if (条件文 2)

    文 2 ;

    else if (条件文 3)

    文 3 ;

    else

    文 4 ;

    今 何度 ? 29

    へぇ、29 度?夏はこれくらいが丁度いい温度ね

    }

    else

    {

    printf("あはは... 異常な暑さで声もでないわ¥n");

    }

    }

  • 平成 27 年 4 月 29 日(水)

    13

    力するようにしよう。また、明治維新以前にあたるところは、自分で工夫

    したメッセージを出力するようにしよう。

    【練習問題 1.6】 次のようなプログラムを作ってみよう。

    1. まず、品物の単価と購入数を入力する。

    2. 次に、消費税額を含めた請求金額を表示する。

    3. 最後に、客の支払った額を入力して、足りればお釣りの額を、足り

    なければ足りない額を出力する。

    【発展問題 1.1】 二次方程式 ax2 + bx2 + c = 0 の解を出力するプログラムを作ってみよう。

    判断式 D = b2 – 4ac が負のときは、解が複素数解であるということを

    出力するようにしよう。

  • 平成 27 年 4 月 29 日(水)

    14

    4. 繰り返し ~for文~

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    【実行結果】

    1

    2

    3

    4

    5

    6

    7

    8

    /* for loop sample 1 */

    #include

    int main(void)

    {

    int i;

    for(i=1;i

  • 平成 27 年 4 月 29 日(水)

    15

    9

    10

    11

    【実行結果】

    【構文】for 文

    for 文は次のように実行されます。

    (1)「式 1」が実行されます。

    (2)「式 2」を評価して条件を満たせば「繰り返す文」を 1 回実行します。

    (3)「式 3」を実行します。ここには、通常繰り返しの数を勘定するための式

    を書きます。

    (4)以後「式 2」の条件を評価しては繰返しを続け、条件が満たされなくなっ

    たら、for 文を終了します。

    この for 文は、主に繰り返しを行う回数がわかっている場合に用いられ、

    例 1-4.1 の 8 行目のように書きます。「」は、変数 i の値を 1 増やすという

    意味です。「i=i+1」と同じ結果になります。

    for 文のフローチャート:

    ** ** ** ** ** ** ** ** ** **

    for (式 1 ; 式 2 ; 式 3)

    繰り返す文 ;

    式 1: ここで繰返しを制御する値の初期設定をする

    式 2: 繰返しを制御するための条件式

    printf("¥n");

    }

    YES

    条件式

    命令文

    NO

    i++

  • 平成 27 年 4 月 29 日(水)

    16

    入れ子になった for 文

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    【実行結果】

    【解説】1.入れ子構造

    for 文を 2 重に使うことで、繰り返しを繰り返すという入れ子構造にすること

    ができます。

    また、繰返しをする文が複数ある場合には、8 行目と 12 行目のように、 { と }

    でくくって、複文にします。

    /* Exercise for loop */

    #include

    int main(void)

    {

    int i,j;

    for(i=0;i

  • 平成 27 年 4 月 29 日(水)

    17

    繰り返し数が変化する入れ子の for 文

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    【実行結果】

    /* Exercise for loop */

    #include

    int main(void)

    {

    int i,j;

    for(i=1;i

  • 平成 27 年 4 月 29 日(水)

    18

    繰り返しの制御変数を減らす

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    【実行結果】

    【解説】

    1.変数を減らす:8 行目の「i--」は、変数 i を 1 減らすというものです。「i=i-1」と同じ結

    果になります。

    /* Exercise for loop */

    #include

    int main(void)

    {

    int i,j;

    for(i=10;i>=1;i--){

    for(j=1;j

  • 平成 27 年 4 月 29 日(水)

    19

    【練習問題 1.8】 以下のような形を表示するプログラムを作ろう。

    【練習問題 1.9】 Nを入力して、1 からNまでの和を計算するプログラムを作ろう。1 から

    Nまでの奇数の和を計算するプログラムも作ろう。

    (1) (2)

    AAAAAAAAA A

    AAAAAAAA AA

    AAAAAAA AAA

    AAAAAA AAAA

    AAAAA AAAAA

    AAAA AAAAAA

    AAA AAAAAAA

    AA AAAAAAAA

    A AAAAAAAAA

  • 平成 27 年 4 月 29 日(水)

    20

    5. do~while文

    繰返しを使って任意個の数の合計を計算する

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    【実行例】

    【構文】do~while 文

    条件式が偽になるまで、do { と } wihie で囲

    まれた文が繰り返し実行されます。文を実行し

    NO

    YES

    /* Add integers till one is zero */

    #include

    int main(void)

    {

    int sum,number;

    printf("データを入力して下さい。0 が入力されたら終了します。¥n");

    sum = 0;

    do{

    scanf("%d",&number);

    sum=sum+number;

    } while ( number!=0 );

    printf("合計 : %d¥n",sum);

    }

    データを入力してください。0 が入力されたら終了します。

    10

    20

    30

    40

    50

    0

    合計: 150

    do {

    繰り返す文 ;

    } while (繰返しを続ける条件) ;

    条件式

  • 平成 27 年 4 月 29 日(水)

    21

    てから条件を判定しますので、文は必ず 1 回は実行されます。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    【実行例】

    【解説】1.プログラムの説明

    2 つの数を入力すると、1 番目の数を 2 番目の数で加えた結果が表示されます。さら

    に、’continue?’ と応答を求めてきますので、これで終わりにしたければ’1’ を、もう一度

    計算をさせたいならば ‘0’ と、応答してください。 ‘0’ と答えた場合は、2 つの数を入力

    するところからもう一度行います。

    /*「Stop」というまで計算を繰り返す。*/

    #include

    int main(void)

    {

    int a,b,ans;

    do{

    printf("¥nEnter two numbers >> ");

    scanf("%d %d",&a,&b);

    printf("The sum is %d",a+b);

    printf("¥n 続けますか? (Contiue :0 Stop:1) ==> ");

    scanf("%d",&ans);

    } while(ans==0);

    printf("¥n");

    }

    Enter two numbers >> 380 140

    The sum is 520

    続けますか? (Continue :0 Stop :1) ==> 0

    Enter two numbers >> 280 180

    The sum is 460

    続けますか? (Continue :0 Stop :1) ==> 1

  • 平成 27 年 4 月 29 日(水)

    22

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    (1) 実行結果は、1-5.2 と同じ。ただ、for 文を使っているので最大で10回の繰り返す。

    最大の繰り返し回数を設けたくない場合はどうするかを考えよう。

    (2)(2)(2)(2) Break 文:if 文の式が「定数」と一致するその右の break 文が実行されます。break

    文ば for 文を終了します。break 文は、while や do whileの繰り返し文にも使えます。

    /* for 文を使って「Stop」というまで計算を繰り返す。*/

    #include

    int main(void)

    {

    int i,a,b,ans;

    for (i=0; i

  • 平成 27 年 4 月 29 日(水)

    23

    6. while文

    割り算を引数で代行する。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    【実行例】

    【構文】while 文

    1. 条件式が真(true)である間「文」を実行します。

    まず、条件式を判定するので、初めから条件式が偽

    (false)の時は文は一度も実行されません。繰り返し

    たい文が複数ある時は、 { と } でくくって、複文

    にします。

    NO

    YES

    /* X / Y ? */

    #include

    int main(void)

    {

    int x,y,syou;

    printf("2 整数を入力 ==> ");

    scanf("%d %d",&x,&y);

    syou=0;

    while(x>=y){

    x=x-y;

    syou=syou+1;

    }

    printf("商: %d 余り: %d¥n",syou,x);

    }

    2 整数を入力 ==> 100 7

    商: 14 余り: 2

    while (条件式)

    文 ; 条件式

  • 平成 27 年 4 月 29 日(水)

    24

    【発展問題 2.2】 x>0 である x と、y≦0 である y を入力すると、このプログラムは終了

    することが出来ません。y=0 が入力されたときは、ゼロで割ろうとして

    いるという警告を表示して終了する。また、x の正負に関わらず正しく結

    果を求めるプログラムを作ろう。(この問題は難問です)

  • 平成 27 年 4 月 29 日(水)

    25

    7. 繰り返しのまとめ

    繰り返しについては、3 種類の文を学びました。各々の特徴をよく理解して下さい。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    1

    2

    /* for 文 */

    #include

    int main(void)

    {

    int Count;

    for(Count=1;Count

  • 平成 27 年 4 月 29 日(水)

    26

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    【実行結果】 3 つとも同じ実行結果になります。

    【注意】 while 文や do~while 文で繰り返す文の中に、必ず繰り返しが終了する条件にな

    る文、すなわち while 文では条件式を満たさないようになる文、do~while 文では

    条件式を満たさないようになる文を含めます。さもないと、無限ループに陥ってし

    まい、参考に記されている方法で止めざるをえません。

    【参考】1.実行中のプログラムを途中で止める(中断、abort)には、

    1) すぐ[CTRL]キーを押しながら[BREAK]キーも同時に押します。

    2) プログラムの実行が中断されます。

    3) 任意のキーを押すとメニューに戻ります。

    **

    **

    **

    **

    **

    **

    **

    **

    **

    **

    int main(void)

    {

    int Count;

    Count=1;

    while(Count

  • 平成 27 年 4 月 29 日(水)

    27

    【練習問題 1.10】 キーボードから次々と入力されるデータの最大値を求めるプログラム

    を作ろう。

    【練習問題 1.11】 5~7 節で作ったプログラムを for 文や do~while 文、while 文で書い

    てみよう。

    【練習問題 1.12】 どんな正の整数でも、偶数だったらその数を 2 で割り、奇数だったら

    3 掛けて 1 足すということを繰り返していくと、いずれ 1 になるという。

    例えば、3 だったら、3→10→5→16→8→4→2→1 という具合になる。こ

    のことを、計算機で試してみよう。そして、各々の数が何回で 1 に到達す

    るかを調べてみよう。

  • 平成 27 年 4 月 29 日(水)

    28

    第 2 章 応用

    1.変数の型と書式の設定の仕方

    書式の設定の仕方

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    【実行結果】プログラムの各文と実行結果を見比べてみよう。

    【解説】1.printf と関数

    これまで入出力の手続きとして用いてきた printf や scanf のように、ある定

    められた処理を行うものを関数といいます。その処理を行うために必要な情報

    が関数に対して与えられます。また、処理された結果、値が得られることもあ

    ります。

    printf では、書式制御文字列、出力する値のリストが関数に与えられて出力

    処理が実行されます。また、scanf では、書式制御文字列が与えられて入力処

    /* 出力書式の指定 int */

    #include

    int main(void)

    {

    int i,j;

    i=48; j=65;

    printf( "%d %d¥n", i, j ); /* 正数で出力する */

    printf( "%5d %5d¥n", i, j ); /* 5 桁で出力する */

    printf( "%-5d %-5d¥n", i, j ); /* 左端にそろえる */

    printf( "%05d %05d¥n", i, j ); /* 0 で埋めることも出来る */

    printf( "%+d %+d¥n", i, j ); /* 符号もつけられる */

    }

    48 65

    48 65

    48 65

    00048 00065

    +48 +65

  • 平成 27 年 4 月 29 日(水)

    29

    理が行われ、結果入力された値が変数に得られます。

    関数の大ざっぱな説明をしましたが、詳細は第 3 章で説明します。

    2.書式を定める

    printf 関数では、書式制御で、%に続いて型しか指定していない場合、出力の

    仕方は処理系の方で適当に定められます。ところが、例題のように、%と型の

    指定の間に更に記号をつけ加えることで、何桁で出力する・左側に揃えるなど

    の出力形式を指定することができます。ここでは、代表的なものだけをあげて

    いきますので、もっと詳しく知りたい人は、市販の文献かマニュアルを参照し

    て下さい。

    3.整数の場合

    <書き方> printf ( "%3d" , i )

    <動作> 変数 i の値を、符号も含めて少なくとも 3 桁で出力する

    ここでいう「少なくとも」とは、例えば「%3d」という書式の設

    定をした場合、出力するのに 3 桁も入らない値に対しては、3 桁の幅

    で値を出力し、3 桁を超えるような値については、必要な桁数だけ出

    力します。

    (例) 値 出力結果

    1 □□1

    10 □10

    1000 1000

  • 平成 27 年 4 月 29 日(水)

    30

    実数型

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    【実行結果】

    【解説】

    1.float 型の出力

    出力桁数を定めたいときには、10 行目のように、”%7.2lf”と書けば、7 桁の幅

    に小数点第 2 位まで値を出力します。

    2.指数形式の出力

    11 行目のように”%e”を用います。出力桁数を定めたい場合、%12.7e”と書け

    ば、12 桁の幅に小数点第 7 位まで値が出力されます。

    実行結果の、「7.366548e+000」は、「7.36….×100」という意味です。これは

    非常に大きい値や非常に小さい値を出力するときに使います。

    /* 型の指定 float と double */

    #include

    int main(void)

    {

    float b, pp;

    b = 7.3665481;

    */

    printf("%f %7.2f¥n",b,b); /* 実数 */

    printf("%e %12.7e¥n",b,b); /* 実数の指数表示 */

    printf("%E %12.7E¥n",b,b); /* こんな指数表示も出来る */

    }

    7.366548 7.37

    7.366548e+000 7.3665481e+000

    7.36 E+000.3665481e+000

  • 平成 27 年 4 月 29 日(水)

    31

    【練習問題 2.1】 出力の書式を工夫して、お店のレシートを作るプログラムを作ろう。単

    価、個数など必要な情報はキーボードから入力すればよい。

    【練習問題 2.2】 次のような九九の表を書くプログラムを作ろう。

    大きい整数の値 long

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    【実行結果】

    1 2 3 4 5 6 7 8 9

    1 1 2 3 4 5 6 7 8 9

    2 2 4 6 8 10 12 14 16 18

    3 3 6 9 12 15 18 21 24 27

    4 4 8 12 16 20 24 28 32 36

    5 5 10 15 20 25 30 35 40 45

    6 6 12 18 24 30 36 42 48 54

    7 7 14 21 28 35 42 49 56 63

    8 8 16 24 32 40 48 56 64 72

    9 9 18 27 36 45 54 63 72 81

    /* 型の指定 int と long */

    #include

    int main(void)

    {

    Short i;

    int k;

    i=20000;

    k=33000;

    printf( "%hd %d¥n", i, k );

    printf( "%10d¥n", (int)i*2 ); /* 型変換(キャスト) */

    }

    20000 33000

    40000

  • 平成 27 年 4 月 29 日(水)

    32

    【解説】1.整数の大きさ

    整数には int 型、short 型、long 型の 3 つの種類があります。short 型で取り

    扱える範囲は、-32768~32767 と決まっており、それよりも大きい値は long

    型で取り扱います。取り扱える範囲は、-2147483648~2147483647 です。(10

    桁という目安でいいでしょう)もう 1 つの int 型は処理系に依存します。

    2.short 型、及び long 型の値の出力

    12 行目のように、それぞれ”%hd”、”%ld”を用います。出力桁数を定めたいと

    きには、13 行目のように、”%10ld”と書けば、少なくとも 10 桁の幅に値を出

    力します。

    3.short 型から long 型への型変換

    例では、13 行

    目の「i*2」は、20000×2 で、40000 になってしまい、short 型で取り扱える

    範囲から外れてしまいます。そこで、前に(int または long)を付加すること

    によって、型を変換(キャスト)して扱います。すなわち、short 型の整数 i の値

    を long 型に変換して 2 をかけます。

    【型のまとめ】 これまでにあげた型の他にも色々な型があります。

    型名 値の範囲

    char

    int (long)

    short

    float

    double

    -128~127

    -2147483648~2147483647 ※

    -32768~32767

    3.4×10???~3.4×10??

    1.7×10????~1.7×10???

    ※:値の範囲は本来、処理系に依存しています。ほぼ確実にどの処理系でも大丈夫な

    のは char くらいです。Double は、倍精度実数型といいます。

    【型変換とキャスト】 C 言語では、型の異なる 2 数の演算ができます。その際、結果は

    double > float > int > short > char

    の順位で、上位の型に変換されます。例えば、float 型と int 型の値の演算の結

    果は float 型になります。

  • 平成 27 年 4 月 29 日(水)

    33

    一方、例 2-1.2 の 13 行目のように、強制的に型を変換する必要が出てくるとき

    には、( )で変換した結果の型名を囲んで、変換したい変数に前置します。こ

    れをキャストするといいます。

  • 平成 27 年 4 月 29 日(水)

    34

    3.配列

    変数に添え字を付けて、順序づけて並べられたいくつかの値を持つ変数を配列といいます。

    添え字をうまく利用すると、沢山のデータの扱いが非常に便利になります。例 1-2.5 の文字

    列は、char 型の配列でしたが、int や float の配列もよく使用されまう s。

    各データと平均値との差を出力する。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    /* 配列に値を入れて計算してみる */

    #include

    int main(void)

    {

    int i,sum,dat[10];

    float average;

    for(i=0;i

  • 平成 27 年 4 月 29 日(水)

    35

    【実行結果】

    【解説】1.配列

    2.配列変数の宣言

    配列を使うときは、以下のような形で宣言します。このとき、[10]と宣言され

    いいたら、添え字は 0~9 までの整数となります。

    1 番目のデータ ==> 65

    2 番目のデータ ==> 79

    3 番目のデータ ==> 94

    4 番目のデータ ==> 61

    5 番目のデータ ==> 50

    6 番目のデータ ==> 85

    7 番目のデータ ==> 90

    8 番目のデータ ==> 70

    9 番目のデータ ==> 64

    10 番目のデータ ==> 59

    総和:717

    平均: 71.70

    1 番目と平均との差 ==> -6.70

    2 番目と平均との差 ==> 7.30

    3 番目と平均との差 ==> 22.30

    4 番目と平均との差 ==> -10.70

    5 番目と平均との差 ==> -21.70

    6 番目と平均との差 ==> 13.30

    7 番目と平均との差 ==> 18.30

    8 番目と平均との差 ==> -1.70

    9 番目と平均との差 ==> -7.70

    10 番目と平均との差 ==> -12.70

    型名 配列名[要素の数] ;

  • 平成 27 年 4 月 29 日(水)

    36

    【練習問題 2.5】 ふたつの 3 次元ベクトルの内積を計算するプログラムを作ってみよう。

    内積は次の式に基いて計算すればよい。

    3

    S=ΣAiBi i=1

    【練習問題 2.6】 トランプをシャッフルすることを考えたい。52 種類のカードを 0 から

    51 の数に対応させるとして、0 から 51 までの数をでたらめに並べるプロ

    グラムを作ってみよう。次の考え方を参考にしてみればよい。

    1. 大きさ 52 の配列 A に、0 から 51 までの数を入れておく。

    2. 0≦IR≦51 に?なる整数乱数 IR をふたつ得る。(M、N とする)

    3. A[M]と A[N]の値を入れ換える。(どうするか?)

    4. 2 と 3 を自分で決めた回数だけ繰り返す。

  • 平成 27 年 4 月 29 日(水)

    37

    4.文字と文字列・配列とポインター

    文字コード表を表示します

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    /* Character Code Table */

    #include

    int main(void)

    {

    int i,j,k,lim;

    for(i=1;i

  • 平成 27 年 4 月 29 日(水)

    38

    【実行結果】

    【解説】1.文字列(char)

    値として文字をとる型を char といいます。char 型は、文字コード 127 まで

    の範囲を取り扱います。実行結果の右の列が文字列で、左の列がコードです。

    2.文字コード

    普段キーボードから入力している文字というのは、一文字一文字に対して文

    字コードが定まっています。英数字については、世界的に共通で、通称 ASCII

    (アスキー)コードといわれています。

    カナ文字は JIS で定められていますが、こちらの方はコードが char で取り扱

    う範囲外ですので、変数としては、unsigned char か int を使います。

    <注意> 0 から 31、127 は制御コードなので、上のプログラムでその文字を画面に

    出力しようとはしないで下さい。

    <参考> 改行制御のコードはこの範囲に含まれており、あえてこれを出力するため

    に printf で”¥n”を用いています。’¥’という文字には特別な意味があり、キー

    ボードから書式制御文字列に直接書けない文字を記述するためのものです。

    code ch code ch code ch code ch code ch code ch

    32 48 0 64 @ 80 P 96 , 112 P

    33 ! 49 1 65 A 81 Q 97 a 113 q

    34 “ 50 2 66 B 82 R 98 b 114 r

    35 # 51 3 67 C 83 S 99 c 115 s

    36 $ 52 4 68 D 84 T 100 d 116 t

    37 % 53 5 69 E 85 U 101 e 117 u

    38 & 54 6 70 F 86 V 102 f 118 v

    39 ‘ 55 7 71 G 87 W 103 g 119 w

    40 ( 56 8 72 H 88 X 104 h 120 x

    41 ) 57 9 73 I 89 Y 105 i 121 y

    42 * 58 : 74 J 90 Z 106 j 122 z

    43 + 59 ; 75 K 91 [ 107 k 123 {

    44 ’ 60 < 76 L 92 ¥ 108 l 124 |

    45 - 61 = 77 M 93 ] 109 m 125 }

    46 . 62 > 78 N 94 ^ 110 n 126 _

    47 / 63 ? 79 O 95 _ 111 o

  • 平成 27 年 4 月 29 日(水)

    39

    その後に続く記号と合わせて、その特別な文字のコードと解釈しています。’¥’

    という文字を画面に出力したい場合には、書式制御文字列の中に”¥¥”と書き

    ます。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    /* アドレスと文字列を理解しよう */

    #include

    #include

    int main( void )

    {

    int i;

    /* char *buf = "abcd123"; */

    char buf[] = "abcd123";

    /*

    * Cleos オリジナル(bug ?)

    * strcpy( buf, "abcd123" );

    */

    printf( "文字列の中身:%s¥n", buf );

    /*

    * Cleos オリジナル(処理系依存)

    * printf( "文字列 buf の先頭アドレス : %5d¥n", buf );

    */

    printf( "文字列 buf の先頭アドレス : %5lu¥n", buf );

    printf( "buf 文字 コード アドレス¥n" );

    for( i=0; i

  • 平成 27 年 4 月 29 日(水)

    40

    【実行結果】アドレスは必ずしもこの値になるとは限りません。

    【解説】1.文字列

    文字の集まりからなる値を、文字列と呼びます。文字列は、文字型の配列と

    して表されます。しかし、他の言語と比べて特徴的なのは、必ず文字列の最後

    に、ヌルコード(値が 0)が入ることです。そのため、必要な字数+1 文字分

    の要素をとる必要があります。

    なお、実行結果の buf[7]の表示で、コードとアドレスが 1 桁ずれているのは、

    このヌルコードを画面に表示しようとはしないからです。

    2.アドレス

    計算機でプログラムを実行するとき、変数の値は結局は計算機の内部の「メ

    モリ」というところに蓄えられます。そのメモリ内での場所のことを「アドレ

    ス」といいます。

    変数各々についてそのアドレスを知ることは、各々の変数がメモリのどこに

    あるかを知ることのなります。変数 A のアドレスは、14⇒26 行目のように&

    を前置して参照できます。

    例題では、’a’という文字が、メモリ中の 66 番地にあるということを表してい

    ます。

    3.配列のアドレス

    配列は、メモリ中で 1 か所にまとまっていて、添え字が 0 の要素が一番先頭

    にあります。

    文字列の中身:abcd123

    文字列 buf の先頭アドレス: 66

    buf 文字 コード アドレス

    [0] a 97 66

    [1] b 98 67

    [2] c 99 68

    [3] d 100 69

    [4] 1 49 70

    [5] 2 50 71

    [6] 3 51 72

    [7] 0 73

  • 平成 27 年 4 月 29 日(水)

    41

    例題では、配列の buf[ ]の先頭アドレスは「buf」とも書けますし、「&buf[0]」

    とも書けます。ところで、13⇒26 行目で「&buf[0]」を、「&buf[2]」にすると

    どういう結果になるか?調べてみましょう。

    4.配列の初期化

    7⇒9 行目のように、宣言時に配列に初期値を与えることができます。このと

    き、添え字は省略できます。

    アドレスとポインターを理解しよう

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    /* アドレスとポインターを理解しよう */

    #include

    #include

    int main( void )

    {

    int a=128, b=256, *pa, *pb, tmp;

    pa = &a;

    pb = &b;

    /*

    * Cleos オリジナル(処理系依存)

    * printf( "a : 値 = %d アドレス = %d¥n", a, pa );

    * printf( "b : 値 = %d アドレス = %d¥n", b, pb );

    */

    printf( "a : 値 = %d アドレス = %lu¥n", a, pa );

    printf( "b : 値 = %d アドレス = %lu¥n", b, pb );

    printf( "¥n 入れ替え後¥n" );

    tmp = *pa; *pa = *pb; *pb = tmp;

    /*

    * Cleos オリジナル(処理系依存)

    * printf( "a : 値 = %d アドレス = %d¥n", a, pa );

    * printf( "b : 値 = %d アドレス = %d¥n", b, pb );

    */

    printf( "a : 値 = %d アドレス = %lu¥n", a, pa );

    printf( "b : 値 = %d アドレス = %lu¥n", b, pb );

    }

  • 平成 27 年 4 月 29 日(水)

    42

    28

    【実行結果】

    【解説】1.ポインター

    アドレスを情報として持つ変数のことをポインターといいます。ポインター

    は、7 行目のようにして、「型名 *ポインター変数名」と宣言します。ポンタ

    ーが p のとき、アドレス p に入っている値は、15⇒20 行目のように、p に*を

    前置して参照ができます。

    例題の場合、変数 a と b のアドレスをポインターpa と pb に代入しています。

    やりたいことは a と b の値を入れ替えることですが、「pa が刺し示す値」を別

    に用意しておいた tmp に入れておいて、そして「pb が指し示す値」を pa とい

    う場所に収め、あけておいた tmp を pb に収めます。

    2.変数の初期化

    7 行目の a や b のように、配列と同様に、変数の初期化ができます。

    a:値=128 アドレス=3560

    b:値=256 アドレス=3556

    入れ替え後

    a:値=256 アドレス=3560

    b:値=128 アドレス=3556

  • 平成 27 年 4 月 29 日(水)

    43

    5.ファイル

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    /* 例2−3.2の結果をファイルに出力 */

    #include

    #include

    int main(void)

    {

    int i,sum,dat[10];

    float average;

    FILE *fp;

    char fname[20];

    for(i=0;i

  • 平成 27 年 4 月 29 日(水)

    44

    33

    34

    35

    36

    37

    38

    39

    40

    【実行結果】

    ※注 「A:¥は、そのファイルを収めておきたいフロッピーディスクのある

    ドライブ名です。パソコンによって違うので注意してください。

    【解説】1.ファイル

    皆さんが普段から作っているプログラムは通常フロッピーディスクに保存し

    ます。そのフロッピーディスクに保存できるのはプログラムだけではなく、文

    書(テキスト)や出力結果も保存できるのです。それらのものをファイルとい

    います。情報の書き込んである「ノート」だと思ってください。

    2.ファイルへの出力

    これまでの例題では、出力は画面で行ってきましたが、ファイルに出力する

    こともできます。結果の出力されたファイルはプログラム同様保存できますし、

    再度プログラムを実行しなくても、印刷することもできます。

    1 番目のデータ ==> 80

    2 番目のデータ ==> 65

    3 番目のデータ ==> 55

    4 番目のデータ ==> 77

    5 番目のデータ ==> 89

    6 番目のデータ ==> 75

    7 番目のデータ ==> 69

    8 番目のデータ ==> 45

    9 番目のデータ ==> 60

    10 番目のデータ ==> 93

    出力ファイル名 >> a:2-5-1.dat ※

    ファイル a:¥2-5-1.dat に結果を出力しました

    fprintf( fp, "総和 : %d¥n", sum );

    fprintf( fp, "平均 : %6.2f¥n", average );

    fclose(fp);

    }

  • 平成 27 年 4 月 29 日(水)

    45

    3.ファイルの開け閉め

    ファイルの入出力をするためには、ファイルの名前を指定するなどの処理を

    しなければいけません。この処理を、ファイルを開くといいます。「読み書き

    をするために『ノート』を開ける」という操作です。

    また、ファイルに対する入出力が終わったら、「『ノート』を閉じる」ことに

    相当する処理をしなければいけません。この処理を、ファイルを閉じるといい

    ます。

    4.ファイルの開け方

    ファイルを取り扱うときに、ファイルポインターという特別な変数を用いま

    す。これは、9 行目のように宣言します。

    そして fopen 関数を用いてこの値を決めます。その際、ファイル名と、ファ

    イルに書く場合”w”を指定します。

    もし、何らかの理由でファイルを開くことができないと、fp の値が NULL(こ

    れは、おまじないとして使っている stdio.h の中で定義されている)になりま

    す。この場合ファイルに対して処理ができないので、代わりの処理をプログラ

    ムに書く必要があります。例題では、exit 関数を用いてプログラムを終了させ

    ています。

    5.プログラムの途中での終了

    <関 数> exit

    <使い方> #include

    exit( status );

    <動 作> status は int 型で、プログラムを呼び出す側に返す値です。通常、

    異常終了でなければ 0 を、異常であれば非 0 を返します。

    6.ファイルに出力する

    <関 数> fprintf

    <使い方> #include

    fprintf( fp, 書式制御文字列, 出力するもののリスト );

    <説 明> ファイル fp に、変数の値を書式制御文字に書かれている書式通り

    に出力します。fp 以外のところの書き方は printf と変わりありません。

    7.ファイルを閉じる

    38 行目のように関数 fclose を用いて、ファイルを閉じます。

  • 平成 27 年 4 月 29 日(水)

    46

    8.出力結果を見るには・・

    「ファイル(F)」メニューの「オープン(F)」を開いて、見たいファイル名

    を指定すると、出力結果をみれます。

    ファイルの内容をディスプレイに表示する

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    【実行結果】

    【解説】1.ファイルを読む

    これまでキーボードから入力してきましたが、フロッピーディスクに入って

    /* ファイルを読んで画面に書く */

    #include

    #include

    int main( void )

    {

    FILE *fp;

    char buf[128], fname[20];

    printf( "ファイル名 >> " );

    scanf( "%s", fname );

    if( (fp=fopen(fname,"r")) == NULL ){

    printf("%s をオープンできません¥n",fname);

    exit(1);

    }

    while( fgets( buf, 128, fp ) != NULL )

    printf("%s",buf);

    fclose(fp);

    }

    ファイル名 >> a:2-4-1.c

    (後略)

  • 平成 27 年 4 月 29 日(水)

    47

    いるファイルから入力することも出来ます。

    ファイルに結果を書き込むプログラムと同様に、fopen 関数を使いますが、こ

    こでは読み込みですので、”r”を使って指定します。

    2.ファイルの 1 行読み込み

    例 2-5.2 は、ファイル名 fname のファイルの内容を画面に出力するプログラ

    ムです。このとき、ファイルの各行の先頭から改行記号までを 1 行として読み

    込むために、関数 fgets を使います。

    <使い方> #include

    fgets( buf, n, fp );

    char buf[]; 読み込む文字列を蓄える配列

    int n; 読み込める最大文字数。これは文字列の最後に着けら

    れるヌルコードの分も含められます。

    <動 作> 読み込む数が n-1 文字になるか改行記号を読むまで、文字列を取り

    込む。もし、ファイルの終わりを示す記号を読むなどで、文字列読み込み不能

    になったら、NULL を返します。

    3.条件式の中で代入が出来る

    C 言語では、13 行目のように条件式の中で代入を実行することがで出来ます。

    解釈としては、「fopen の値を fp に代入し、それが NULL だったら」というこ

    とになります。但し、その部分を括弧でくくる必要があります。例 2-5.1 の 24、

    25 行目と比べてみて下さい。

    【参考】 scanf とほぼ同じ使い方をする fscanf という関数もあります。ただ、

    こちらの方は、改行文字と途中の空白文字を区別せず、「テキストを 1 行読

    む」ということには適さないので使いませんでした。

    【練習問題 2.7】 ファイルをコピーするプログラムを作ろう。復元元ファイルから読み込

    んだデータを複写先ファイルに書き込むという形にすればよい。FILE 型

    変数はふたつ必要になる。プログラムのファイル名は、学習院のパソコン

    で使っている MS-DOS の都合で、copy.c にしないように。

  • 平成 27 年 4 月 29 日(水)

    48

    第 3 章 関数

    1.関数とは何か

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    【実行結果】

    /* 度 から ラジアン */

    #include

    #include /* sin() */

    #define PAI 3.141593

    double rad( double );

    int main(void)

    {

    double ang;

    printf( " 度 radian sin¥n" );

    for( ang=0.0; ang

  • 平成 27 年 4 月 29 日(水)

    49

    【解説】1.関数(Function)

    関数とは、「下請け業者」のようなものです。「下請け」が「親会社」から「品

    物の製造」や「決まった作業」の依頼を受けるように、関数も呼び出されて値

    を新たに計算したり、決まった処理をします。

    これまでところどころで使ってきたprintf( )や scanf( )は実はCの標準で用意

    された関数で、各々データの入出力をするものなのです。

    C のプログラムは、これらの関数の集まりで出来ています。main()は、この

    プログラムが呼び出されて、一番先に呼び出される「一番大きい会社」です。

    そして main()から、いろいろな「下請け」が呼び出されていきます。

    2.引数(Argument)

    「発注元」から「材料などが提供される」ことがあるように、関数を呼び出

    す際にも、呼び出す側から、処理に必要な情報として、すでに出来上がった値

    を渡すことがあります。これが引数というものです。

    3.返り値、関数の型

    関数が行った処理の結果、出来あがった値を「発注元」にただ一つだけ返す

    ことができます。これが返り値というものです。また、返り値の型を関数の型

    といいます。返り値は、21 行目のように return 文を使って返します。

    4.実引数と仮引数

    関数の宣言に書く引数は、いわば「仮の名前」ですから仮引数といいます。

    それに対して、関数を呼び出す側の引数は、実際の名前を書きますので実引数

    といいます。実引数と仮引数は書かれた順番に従って対応しデータが渡されま

    す。

    プログラムでは、呼ぶ側と呼ばれる側で、引き数の型と順番をきちんと対応

    づけなければなりません。また、引き数がない場合でも、必ず両者に括弧を書

    く必要があります。

    5.値渡し(Call by value)とアドレス渡し(Call by reference)

    C 言語の関数の引き数の渡し方には二通りあります。

  • 平成 27 年 4 月 29 日(水)

    50

    上の f1 は、x,y を「材料」としている関数です。この場合、x,y の値は関数内

    に用意された変数 a,bにそれぞれコピーされて使用されます。関数内での a,b

    の値を変更しても x,y には影響しません。

    これを、「値渡し(Call by value)」といいます。例 3-1.1 の関数 rad はその

    例です。

    一方 f2 は s,t に値を得る関数と思ってください。このような複数の値を返す

    場合や、引き数の値を変更したい場合、配列すべてを渡したい場合に、情報と

    して、処理の対象となる値(s や t)のアドレス、即ち&s や&t が、関数内のポ

    インター変数 p や q にコピーされ、関数の中で、そのアドレスに蓄えられてい

    る値を参照したり、そこに新しい値を収めたりします。後者の場合には、関数

    を呼び出した側の s や t に影響が及びます。

    これを「アドレス渡し(Call by reference)」といいます。例題は、例 3-2.1

    であげます。scanf 関数で「&a」と書いていますが、これは入力された値を変

    数 a に入れて返してもらうためにアドレス渡しを行っているのです。

    6.関数の書き方

    main 関数も含めて、関数の書き方の基本形は、以下の通りです。

    void main(void)

    {

    ・・・ ;

    ○○ = f1( x, y );

    fun2 ( &s, &t );

    ・・・ ;

    }

    int fl( int a, int b )

    {

    ・・・ ;

    }

    void f2( int *p, int *q )

    {

    ・・・ ;

    }

    関数の型 関数名(仮引数の宣言)

    {

    処理

    }

  • 平成 27 年 4 月 29 日(水)

    51

    C 言語の規格のちがいで、引数の宣言には二通りの書き方があります。下表

    の左の方は、返り値のない関数に void という型を設けることで、右の方より

    関数の型について厳密な記述をしています。

    本書では左の方を採用しています。学習院で使っている C 言語は、両方共の

    書き方を許しています。

    ANSI(米国規格協会)の規格 C 言語誕生当初の規格

    返り値がない void 関数名(引き数の宣言)

    {

    処理;

    }

    関数名(引き数名)

    引き数の型宣言;

    {

    処理;

    }

    引き数がない

    関数の型 関数名(void)

    {

    処理;

    }

    関数の型 関数名()

    {

    処理;

    }

    引き数は

    例えば char 型

    返り値は

    例えば int 型

    int 関数名(char a)

    {

    処理;

    }

    int 関数名(a)

    char a;

    {

    処理;

    }

    例 3-1.1 では、main()で rad()が呼びだされており、double 型の返り値を main

    に返しています。main 関数は、呼び出し側(C 言語の開発支援メニューのプ

    ログラム)に対して何も返り値を返さないし、引き数もないので、左の書き方

    では void main(void)となります。

    7.関数のプロトタイプ宣言

    関数を使うとき、プログラムの最初に、関数や引き数や返り値の型の約束ご

    とを書いておきます。これを、関数のプロトタイプ宣言といいます。例題では、

    5 行目がそうです。

    返り値の型 関数(引き数の型);

    と書きます。

  • 平成 27 年 4 月 29 日(水)

    52

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    【実行結果】

    /* Summation */

    #include

    int sum( int );

    int main( void )

    {

    int i;

    for ( i = 1 ; i

  • 平成 27 年 4 月 29 日(水)

    53

    【解説】1.ヘッダーファイル

    これまで「おまじない」ということにしておいた例題の 2 行目について説明

    します。

    <と>で囲まれているのは、ヘッダーファイルといい、これには定められた

    いくつかの関数などの約束ごとが書かれています。#include は、コンパイルに

    先だってこれをプログラムに取り込むための制御文です。

    例題によく出てくる stdio.h は、printf や scanf のような標準入出力関数につ

    いての約束ごとが書かれています。その他、代表的な関数とその約束ごとが書

    かれているヘッダーファイル名は、付録に掲載されています。

    例 3-1.1 の関数 rad をマクロ関数にした

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    【実行結果】例 3-1.1 と同じ

    【解説】1.マクロ

    コンパイル時にプログラム中の特定の記号を指定された文字列に置換します。

    これをマクロといい、

    #define マクロ 置き換える文字列

    として定義します。

    例 3-1.3 でいうと、PAI が 3.141593 に置き換えられます。こうしておくと、

    定数の意味付けがはっきりするためプログラムがわかりやすくなります。

    /* 度 から ラジアン */

    #include

    #include /* sin() */

    #define PAI 3.141593

    #define rad(x) (x)*PAI/180.0

    int main(void)

    {

    double ang;

    printf( " 度 radian sin¥n" );

    for( ang=0.0; ang

  • 平成 27 年 4 月 29 日(水)

    54

    2.引き数付きマクロ

    マクロでは、5 行目のように、引き数をとることもできます。ただし、数値の

    引き数である場合、通常置き換える方に括弧を付けておきます。これは、負の

    数であるときに、置き換えた結果構文に矛盾を生じることがあるからです。

    【練習問題 3.1】 ふたつの数を比較して大きい方を返す関数 imax とそれを使うプログ

    ラムを作ろう。

  • 平成 27 年 4 月 29 日(水)

    55

    2.関数を作る

    2 つの値を交換する関数

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    【実行例】

    #include

    void ISwap( int *, int * );

    int main( void )

    {

    int A, B;

    printf( "Enter two integer values: " );

    scanf( "%d %d", &A, &B );

    printf( " A = %d, B = %d ¥n", A, B );

    ISwap( &A, &B );

    printf( "The max is %d ¥n", A );

    }

    /* ふたつの整数を大きい順にする */

    void ISwap( int *I, int *J )

    {

    int Temp;

    if ( *I < *J )

    {

    Temp = *I;

    *I = *J;

    *J = Temp;

    }

    }

    Enter two integer values: 100 200

    A = 100, B = 200

    The max is 200

  • 平成 27 年 4 月 29 日(水)

    56

    【解説】1.アドレス渡し(Call by reference)

    先に説明した通り、渡したい引き数の内容を関数の中で変更したい場合や、

    複数の値を返す場合、「アドレス渡し」を使います。蛇足になりますが、アド

    レスのやりとりがされるので、関数の呼び出される側では、ポインターとして

    引き数の宣言をします。

    例題では、17 行目以降の I や J にはアドレスが入っていますので、処理した

    い値は、*を付けて参照します。

    値を入力する関数と平均を計算する関数

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    #include

    void GetData( int * );

    float average( int * );

    int main( void )

    {

    int A[ 10 ];

    float av;

    GetData( A );

    av = average( A );

    printf( "the average is %9.2f ¥n", av );

    }

    /* データを入力 */

    void GetData( int *X )

    {

    int i;

    printf( "Enter 10 Data: ¥n" );

    for ( i = 0 ; i < 10 ; ++i )

    scanf( "%d", &X[ i ] );

    }

    /* 平均を求める */

    float average( int *X )

    {

    int i, total;

  • 平成 27 年 4 月 29 日(水)

    57

    27

    28

    29

    30

    31

    32

    33

    34

    【実行例】

    【解説】1.関数にすることのメリット

    関数を出来るだけ作って、細かく分業制にすると、プログラム自体がすっき

    りして、このプログラムは何をやっているのかおおまかに把握できます。例

    3-2.2 ではデータを入力して、平均を計算して、出力するというのが手に取る

    ようにわかります。

    また、ひとつのプログラムの中で全く同じ一連の命令を何回も書かなくても

    良くなることがあります。

    2.ローカル変数

    一つの関数の中だけで定義されている変数(例 3-2.2 では average()中の

    total 等)のことを、ローカル関数といいます。

    ローカル関数は、ほかの関数からは参照できません。例 3-2.2 で GetData()

    と、average()で、同じ名前の変数 i を使っていますが、これらはローカル変数

    なので、一方の値が変更されても他方には影響が及びません。

    3.配列を引き渡す方法

    文字列などの配列を関数に引き渡すには、その先頭の番地(ポインター)を

    引き渡します。

    Enter 10 Data:

    (中略)

    the average is 70.20

    int i, total;

    total = 0;

    for ( i = 0 ; i < 10 ; ++i )

    total = total + X[ i ];

    return( ( float )total/10 );

    }

  • 平成 27 年 4 月 29 日(水)

    58

    並べ替え(バブルソート)その 1

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    /* 名前をアイウエオ順にならべる */

    #include

    #include

    #include

    #define TABLESIZE 8

    #define TRUE 1

    #define FALSE 0

    void sort( void );

    char nametable[][ 15 ] = { "まさる", "せいいち",

    "ひでみ", "ぎんしろう",

    "けいこ", "ひろみ",

    "カール", "よしやす" };

    int main( void )

    {

    int i;

    printf( "並べ換え前¥n" );

    for ( i = 0 ; i < TABLESIZE ; ++i )

    printf( "%s¥n", nametable[ i ] ) ;

    sort();

    printf( "¥n 並べ換え後¥n" );

    for ( i = 0 ; i < TABLESIZE ; ++i )

    printf( "%s¥n", nametable[ i ] ) ;

    exit( 0 );

    }

    /* あいうえお順に並べ換える */

    void sort( void )

  • 平成 27 年 4 月 29 日(水)

    59

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    並べ替え(バブルソート)その 2

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    {

    int i;

    char temp[ 15 ];

    int swapped;

    do {

    swapped = FALSE;

    for ( i = 0 ; i < TABLESIZE-1 ; ++i )

    if ( 0 < strcmp( nametable[ i ], nametable[ i+1 ] ))

    {

    strcpy( temp, nametable[ i ] );

    strcpy( nametable[ i ], nametable[ i+1 ] );

    strcpy( nametable[ i+1 ], temp );

    swapped = TRUE;

    }

    } while( swapped ) ;

    }

  • 平成 27 年 4 月 29 日(水)

    60

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

  • 平成 27 年 4 月 29 日(水)

    61

    【解説】1.バブルソートの考え方

    大きい順や小さい順、アイウエオ順など、ある規則の順番にデータを並べ替

    えることを考えます。基本的な考え方は、隣同士の序列を比べて、並べたい順

    序になっていなかったら入れ替えるということです。この操作を全てが正しい

    順序になるまでひとつひとつ行います。

    (1) 隣り同士で入れ替えをしたという印を表す変数 swaped を用意します。デー

    タの先頭から最後までの序列の関係を調べる前に、これを「入れ替えなし」

    (例では FALSE)にしておきます。

    (2) 先頭から最後まで通して序列を調べ、1 回でも入れ替えがあったらそこで

    「入れ替えあり」(例では TRUE)にします。

    (3) 一度通しただけでは大きい順位はなりません。そこで、もう 1 回先頭に戻り、

    swaped を FALSE にして、再び調べます。

    もし、正しい順番になっていたら、通して調べた後 swaped が FALSE のま

    まであるはずですから、そのときを操作の終了とします。

    2.二次元配列

    例題の nametable のように、配列を二次元に取ることができます。宣言は、

    「型名 変数名[要素数 1] [要素数 2];」と書きます。宣言時に初期値を与える

    こともでき、その場合には 11⇒12~15 行目のように書いて、要素数 1(例題

    では 8)は省略できます。

    二次元配列は、ポインターの一次元配列ともみなせ、例えば i 番目の名前だっ

    たら、nametable[i]がその「人」の先頭アドレスになります。また、配列全体

    の先頭アドレスは nametable や nametable[0]、&nametable[0] [0]とも書けま

    す。

    3.グローバル変数

    例 3-2.2 で説明したローカル変数に対して、各関数で参照できる変数のことを、

    グローバル変数といいます。

    例で用いている nametable という配列変数がそうです。これは、関数 sort()

    の中でも、main()でも参照できるので、引数にとる必要がありません。

    4.文字列操作関数

    名前をあいうえお順に並べ替えるときに、2 つの文字列操作関数を使っていま

    す。これらは、C 言語の標準で定められた関数で、string.h をインクルードし

    ます。

  • 平成 27 年 4 月 29 日(水)

    62

    ○strcmp … 文字列の比較

    <引き数> char *s1, char *s2;

    <動 作> 文字列 s1 と s2 を先頭から 1 文字ずつ比較して、文字コードの

    順で s2 の方が若ければ正、s1 の方が若ければ負、まったく同じ

    なら 0 を、int 型で返す。この比較において英字の大文字と小文

    字は区別する。

    ○strcpy … 文字列の複写

    <引き数> char *s1, char *s2;

    <動 作> 文字列 s2 を文字列 s1 に複写する。

    5.例題その 1 とその 2 の違い

    例 3-2.3 と例 3-2.4 は同じ結果を得ることができます。しかし、計算機の内部

    では全く異なった処理をします。下に 11 行目の宣言に対する計算機内部での

    メモリーの取り方を示します。

    その 1 では、nametable[8][15]に実際のデータが入っていますが、一方その 2

    では nametable[8]には実際のデータがある番地が入っています。従って、そ

    の 1 での sort()は文字列そのものを移動(45 行~47 行⇒46 行~48 行)させて

    並べ替えを行っていますが、その 2 ではポインターの入れ替え(45 行~47?

    行)だけ行い、データそのものは移動していません。例えて言うならば、その

    1 は列車の乗客を入れ替えているのですが、その 2 は列車番号だけ入れ替えて

    いると考えてください。

    nametable(その 1) nametable(その 2)

    0 まさる 0 まさる

    1 せいいち 1 せいいち

    2 ひでみ 2 ひでみ

    3 ぎんしろう 3 ぎんしろう

    4 けいこ 4 けいこ

    5 ひろみ 5 ひろみ

    6 カール 6 カール

    7 よしやす 7 よしやす

  • 平成 27 年 4 月 29 日(水)

    63

    【練習問題 3.2】 キーボードから 10 個の実数型のデータを入力し、大きい順に並べ替

    えるプログラムを、関数を使って作ろう。

    【発展問題 3.1】 大貧民というトランプのゲームがある。これは、キング(13)よりもエ

    ース(1)や 2 の方が強いとされている。自分の手(12枚くらいでいいだろう。

    キーボードから入力するようにしてみよう)を、弱い順に並び変えるプロ

    グラムを作ろう。

    棒グラフを作る

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    /* データファイルの読み込みと棒グラフの作成 */

    #include

    #include /* exit() */

    #define TABLESIZE 20

    int get_data( int * );

    void disp( int );

    char name[ TABLESIZE ][ 15 ] ;

    int Computer[ TABLESIZE ];

    int English[ TABLESIZE ];

    /* メイン */

    int main( void )

    {

    int num, i;

    if( get_data( &num ) == 1 ){

    printf( "データが読めませんでした¥n" );

    exit( 1 );

    }

    printf( "¥n" );

    printf( " 氏 名 計算機 英語¥n" );

    for( i=0; i

  • 平成 27 年 4 月 29 日(水)

    64

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    /* 個人データを得て、読み込んだ人数を引き数で返す

    読み込めなかったら1を、読み込めたら0を返す */

    int get_data( int *n )

    {

    int i;

    char fname[20];

    FILE *fp;

    printf( "ファイル名 ==> " );

    scanf( "%s", fname );

    if( ( fp=fopen(fname,"r") )==NULL ) return( 1 );

    i = 0;

    while( fscanf( fp,"%s %d %d", name[i], &Computer[i],

    &English[i] ) !=EOF ){

    i++;

    if( i > TABLESIZE ){

    printf( "もうこれ以上読み込めません¥n" );

    break;

    }

    }

    *n = i;

    fclose( fp );

    return( 0 );

    }

    /* i番目の学生の結果を棒グラフに表示 */

    void disp( int i )

    {

    int j, cnt;

    printf( "%15s%5d%5d ", name[ i ], Computer[ i ], English[ i ] );

    cnt = ( Computer[ i ] + English[ i ] )/5;

    for ( j = 0 ; j < cnt ; j++ )

  • 平成 27 年 4 月 29 日(水)

    65

    63

    64

    65

    66

    【データのファイルの例】

    【実行】予めデータファイルをエディターで作っておいてください。

    【解説】1.プログラムについて

    8 人からなるクラスがあり、各人の試験結果(計算機と英語)のデータがあり

    ます。そのデータを、ファイルから入力し、2 科目の合計点に基づいて棒グラ

    フを画面に描きます。

    ファイルから入力、棒グラフの作成をそれぞれ関数として作りました。

    2.データファイルの作り方

    「ファイル(F)」メニューの「新規オープン(N)」を開いて、データファイルを

    作成したのち、任意のファイル名を指定して保存してください。

    さちこ 92 67

    なおこ 50 73

    まさこ 38 82

    ももこ 43 53

    ひさこ 65 89

    れいこ 58 71

    まりこ 44 80

    えりこ 97 55

    ファイル名 ==> a:3-2-5.dat

    氏 名 計算機 英語

    さちこ 92 67 *******************************

    なおこ 50 73 ************************

    まさこ 38 82 ************************

    ももこ 43 53 *******************

    ひさこ 65 89 ******************************

    れいこ 58 71 *************************

    まりこ 44 80 ************************

    えりこ 97 55 ******************************

    printf( "*" );

    printf( "¥n" );

    }

  • 平成 27 年 4 月 29 日(水)

    66

    3.ファイルから読み込む関数 fscanf

    <使い方> fscanf ( fp, 書式制御文字列, 入力変数リスト );

    <動 作> ファイル(ファイルポインターfp)から、scanf と同じ様式で値を

    入力します。もし、ファイルの終わりにあるファイル終了記号を読

    むと、EOF を返します。EOF は、stdio.h で定義されている定数で

    す。

  • 平成 27 年 4 月 29 日(水)

    67

    3.再帰呼び出し

    階乗を計算する関数

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    【実行結果】

    【解説】1.再帰呼び出し(recursive call)

    /* 階乗 */

    #include

    long fact( int );

    int main(void)

    {

    int i;

    for( i=1; i

  • 平成 27 年 4 月 29 日(水)

    68

    関数の中で他の関数を呼び出す例は、1 節や 2 節でみてきました。ここで扱う

    再帰呼び出しとは関数の中から自分自身を呼び出すことをいいます