/* * 課題 CNAME-01 * * CDATE FILENAME * * Hello, World (3 度目) */ #include <stdio.h> /* * main */ int main( int argc, char *argv[] ) { printf ( "Hello, World\n" ); /* 画面に「Hello, World」という文字列と、 その後に、「改行」を表示する => このプログラムを実行すると、 画面に「Hello, World[改行]」が表示される */ return 0; }
/* * 課題 CNAME-02 * * 20210917 20210917-02-QQQQ.c * * 局所変数の宣言と、代入文 * 局所変数の宣言: * 利用する変数名をきめ、その型宣言(変数に代入可能な値の型の指定) * printf の使い方 */ #include <stdio.h> /* * */ /* * main */ int main( int argc, char *argv[] ) { /* 二つの整数型(int)の変数 ia, ib の宣言と、初期代入 */ int ia = 7; int ib = 15; /* 二つの浮動小数点型(double)の変数 da, db の宣言と、初期代入 */ double da = 3.14; double db = 1.59; printf ( "%d + %d = %d\n", ia, ib, ia + ib ); /* 整数型の和 */ /* 結果 ia <= 7, ib <= 15, 22 => ia + ib 7 + 15 = 22 7 + 15 = 22 ^ ^^ ^^ 3 箇所 整数型 ( ia, ib, ia + ib の値 ) %d + %d = %d <= 書式指定 ( printf の最初の引数 ) printf の二つ目以後は、 埋め込む整数型の値の指定 ia, ib, ia+ib !! printf を使うと !! 出力したい結果を念頭において、書式設定ができる !! => 望みに近い形での出力が可能 */ printf ( "%f / %f = %f\n", da, db, da / db ); /* 浮動小数点数の商 */ /* 結果 3.140000 / 1.590000 = 1.974843 */ return 0; }
#include <stdio.h> /* 前期 : 「変数」の導入 関数の「引数」として導入 */ /* 鈴木さんと、田中さんに、挨拶のメッセージ (printf で表示)を送る */ int main(void) { printf ( "こんにちは、" ); printf ( "鈴木さん\n" ); printf ( "こんにちは、" ); printf ( "田中さん\n" ); return 0; }
#include <stdio.h> /* 前期 : 「変数」の導入 関数の「引数」として導入 */ /* 鈴木さんと、田中さんに、挨拶のメッセージ (printf で表示)を送る 関数版 */ /* それぞれの人に挨拶をする関数を個別に作成 */ /* 関数「suzuki」の定義 */ /* { ? } の内容に、「suzuki」という名前をつけた 「suzuki」という関数の本体(中身)が { ? } */ void suzuki (void) { printf ( "こんにちは、" ); printf ( "鈴木さん\n" ); } void tanaka (void) { printf ( "こんにちは、" ); printf ( "田中さん\n" ); } int main(void) { suzuki(); /* 関数「suzuki」の呼び出し */ /* 関数「suzuki」の内容が実行される */ /* 「suzuki」という名前をつけた命令が実行される */ tanaka(); return 0; }
#include <stdio.h> /* 前期 : 「変数」の導入 関数の「引数」として導入 関数の「仮引数『変数』」 変数は、(実引数変数で指定する事により..) 色々な「値」を取りうる「物」である (すくても、命令が実行される時[実行時]には) その変数の値が、確定していないといけない !! プログラムを作る時は、値が未定でよい => 実行時に変数の値を決める操作が必要 仮引数変数の場合は、 関数呼び出しの実引数を指定する事が、 それに相当する */ /* 鈴木さんと、田中さんに、挨拶のメッセージ (printf で表示)を送る 引数付き関数版(変数の導入) */ /* それぞれの人に挨拶をする関数を個別に作成 */ /* 二つの関数(suzuki, tanaka)の内容(本体)は、 よく似ている(違う部分があるために同じにならない) => 違う部分だけ、「変数化」(共通の変数名[表記]になるので) => 「同じ」にできてしまう */ void aisatu ( char *X ) { printf ( "こんにちは、" ); printf ( X ); /* 異なる部分を「X」という変数にする */ } /* suzuki() <-> aisatsu で、かつ X が 「鈴木さん\n」の時 tanaka() <-> aisatsu で、かつ X が 「田中さん\n」の時 引数付き関数 似たような関数を変数を利用して、抽象化し、まとめる */ void suzuki (void) { /* printf ( "こんにちは、" ); printf ( "鈴木さん\n" ); */ aisatu ( "鈴木さん\n" ); /* 関数 aisatsu を呼び出す時に、 引数変数 ( この例では変数 X ) に当てはまる値を指定する (実引数) */ } void tanaka (void) { /* printf ( "こんにちは、" ); printf ( "田中さん\n" ); */ aisatu ( "田中さん\n" ); } int main(void) { suzuki(); /* 関数「suzuki」の呼び出し */ /* 関数「suzuki」の内容が実行される */ /* 「suzuki」という名前をつけた命令が実行される */ tanaka(); aisatu ( "高橋さん\n" ); /* 引数付き関数を作成する事により、 様々な実引数に対して、処理をする事が可能になる */ return 0; }
#include <stdio.h> /* 前期 : 「変数」の導入 関数の「引数」として導入 関数の「仮引数『変数』」 */ void aisatu ( char *X ) { printf ( "こんにちは、" ); printf ( X ); /* 異なる部分を「X」という変数にする */ } int main(void) { aisatu ( "高橋さん\n" ); /* aisatu("高橋さん\n") <=> X <- "高橋さん\n" <= 変数 X に代入が行われている printf ( "こんにちは、" ); printf ( X ); <=> printf ( "こんにちは、" ); printf ( "高橋さん\n" ); => 「こんにちは、高橋さん[改行]」が表示される */ return 0; }
#include <stdio.h> /* 前期 : 「変数」の導入 関数の「引数」として導入 関数の「仮引数『変数』」 */ int main(void) { char *X; /* 変数 X の宣言 */ /* 関数の仮引数変数宣言の代わり、 (auto 変数/局所変数)変数宣言が必要 */ /* aisatu ( "高橋さん\n" ); 関数をなくして、元に戻す */ /* 変数 X に「"高橋さん\n"」という値を代入したい !! 関数呼び出しなら、実引数の指定 !! 新しい方法を紹介する */ X = "高橋さん\n"; /* 変数 X に対する代入操作 */ /* 「代入」には記号「=」を使うが、 これは、「等号(等しい)」(という意味)ではない !! そもそも、逆にできない !! 「"高橋さん\n" = X」は、意味が違う(この場合は、こうできない) 「代入」には方向性があって 左辺にある「変数」に右辺の式の値が「代入される」 cf. Pascal 言語では、代入には「:=」を使う X := "高橋さん\n"; */ printf ( "こんにちは、" ); printf ( X ); /* printf ( "こんにちは、" ); printf ( "高橋さん\n" ); */ return 0; }
#include <stdio.h> /* 前期 : 「変数」の導入 関数の「引数」として導入 関数の「仮引数『変数』」 */ int main(void) { char *X; /* 変数 X の宣言 */ /* 変数 X には、(明示的な..)「値」はない */ /* !! 実際は、「ゴミ」が入っているので、 !! 最初の代入(変数の初期化)が行われるまでは、 !! その変数(の値)を参照(変数の値を問う[取り出す])してはいけない */ X = "高橋さん\n"; /* 変数 X の値は(直前の代入の結果)「"高橋さん\n"」になっている */ printf ( "こんにちは、" ); printf ( X ); /* 変数 X の値が参照されて、「"高橋さん\n"」が値として利用される */ /* 参照されても、変数の値は変更されない */ /* => 必要ならば、何度でも、同じ(変数を利用して)値を取り出す事ができる */ printf ( "こんにちは、" ); printf ( X ); /* 変数 X の値がもう一度参照され、同じが使われる */ /* 変数を利用するメリット => 変数に、同じ値を代入しておくことにより、 同じ値を何度でも利用できる !! 変数に、「計算した結果」を代入する事により、 !! 同じ値の計算を、二度としなくても済む !! => 効率化 !! !! 昔の計算機は、遅かった !! !! => できるだけ無駄を省く !! !! => 代入が基本操作 !! !! !! 効率的なアルゴリズムのいくつかは !! !! !! => もともとの(定義にあった)計算の中から、(代入等を利用して..)無駄を省く事により効率化している */ X = "鈴木さん\n"; /* 変数 X に再度代入が行われる */ /* 変数 X がもっていた前の値(「高杯さん\n」)は、失われる */ /* => 変数 X を利用して、その値を取りだす事ができない */ /* 「上書き」がおきる */ printf ( "こんにちは、" ); printf ( X ); X = "田中さん\n"; printf ( "こんにちは、" ); printf ( X ); return 0; }
#include <stdio.h> int main(void) { printf ( "単純に文字列をそのまま出力する\n" ); /* これまでの printf の使い方 */ /* 新しい使い方 最初の引数は、「書式指定」を含む文字列で、 実際に出力したい値は、その後に続く引数で指定をする */ printf ( "%s", "abc\n" ); /* %s : 文字列を出力する書式 */ /* ^^^ ^^^^^^ ↑ | +--------+ 書式指定の場所に、後の引数の値が埋め込まれる */ /* 画面に「abc[改行]」が表示される */ /* printf の書式指定は、「%」から始まる文字列で行う */ printf ( "(%s)", "abc\n" ); /* %s : 文字列を出力する書式 */ /* %s のところだけが、"abc\n" */ /* => (abc\n) に変化する */ printf ( "\n" ); printf ( "(%s)\n", "abc" ); /* %s : 文字列を出力する書式 */ /* %s のところだけが、"abc" */ /* => (abc)\n に変化する */ printf ( "(%d)\n", 123+456 ); /* %d : 整数値を出力する書式 */ printf ( "(%f)\n", 1.23 * 4.56 ); /* %f : 浮動小数点数を出力する書式 */ return 0; }
#include <stdio.h> int main(void) { int a=123; double b=1.23; printf ( "int a=%d, double b=%f\n", a, b ); /* ^^ ^^ | | | | | | +------------|-----+ | +--------+ */ return 0; }
前回の内容 前回の内容 ガイダンス : 基本は、前期と同じ / ただし、前期の知識を仮定する 目的 : 「C 言語でプログラムが書けるようになる」事 三つの内容 : プログラミング / 操作方法 / C 言語 方針 : 同じ内容を 3 度、繰返しながら、少しずつ内容を深く進める 復習 1 周回 : hello world, 関数, 制御構造(順接,条件分岐,再帰) 原理的に可能なプログラムは一通りかける 2 周目 : 様々なデータ構造 ( char, int ) まだ、途中 : 早めに終らせて、3 周回のアプリ開発に行きたい 代入 代入とは 概念 : 「変数」に「値」を「割り当て」る「操作」 「変数」 関数の引数変数として導入 色々値を持ちうるもの プログラム作成時は、値がきまってなくてもよいが 実行時には、値が決まっている必要がある => 「値を決める」という作業 => 「値」を「割り当てる」 例: 仮引数変数の場合は、 実引数(これが割り当てる変数の値)が相当する => 実引数を指定(して、関数を呼び出しを)する事は、 仮引数変数への代入 「=」を利用した代入の話 代入「後」は、その変数の値は、代入さ(割り当てら)れた値に「変化」する 1 限の内容 a. 「代入」という言葉 b. 「代入」の仕組み => 関数引数と同じ働き c. 「代入」を C 言語で(関数呼び出しを使わず、直接)実行する方法 代入文 ( 「=」を利用した、代入の表現 ) (代入文の左辺に現れる変数を利用するための..) 変数宣言 => 関数の仮引数変数と同じ 表 : 代入文と関数呼び出しの比較 代入の対象 代入元 タイミング 回数 影響範囲 代入文 局所変数 代入文の右辺の式 いつでも 何度でも 次の代入まで 関数呼び出し 仮引数変数 実引数 関数呼び出し時 一回 関数(呼び出し)内 代入を行うと (その変数が保持していた..) 代入「前」の値は、「失われ」る 代入の「前」と「後」という「時間」の概念の把握が必要となる !! 数学には「時間の概念がない」 表現 : 代入の構文 「変数名」=「式」 [例] a=1+2; (変数 a に 3 ( = 1+2 ) を代入) => 代入文は、「式の『計算』要求」にもなっている => 代入文を並べる事により、 「計算を進める」事にもなっている 手続き型言語 ( 代入文を中心にプログラムを書く事を想定した言語 ) 「=」は、「代入」を表現する(等号[等しい]ではない!! / 等号は「==」) 局所変数宣言 概念 : 局所変数を宣言する cf. 関数の仮引数変数は、関数の定義時に、仮引数部でおこなっている 関数の本体 ( { ? } : ブロック ) の先頭でやる # C 言語の制約のひとつ / C++ などは、先頭に限定しない.. => プログラミング時は、変数の型を指定し、 変数に代入可能な値の制限を行う 実行時は、変数の値を収める領域を準備する命令になる 関数(ブロック)内のみ(局所的)で有効(利用可能)な変数を宣言する 「仮引数変数(実は局所変数の一種)」以外にも、変数が増やせる !! 仮引数変数も代入文をつかって、値が変更できる 表現 : 局所変数の宣言 「変数の型名」「変数名」 [例] int a; (整数型の変数 a を宣言) cf. 仮引数変数は、実引数の値で、「代入済」の変数 -> 局所変数は宣言をした段階では、「ゴミ」が入っている 未代入の変数の値は「未定(プログラムミスの代表例 !!)」 変数は宣言と同時に「初期化(最初の代入)」できる(すべき) [例] int a=1; !! 最初に何をいれるべきかがわからない場合がある !! 変数を使いたい場所と、宣言をする場所が離れているから !! その場合は、「固定」な値を無条件に設定する !! 例 : int 0/char '\0'/char * "" 課題 : 20210917-02 => 後回し 標準 I/O ライブラリの利用 標準 I/O ライブラリ ( stdio ) I/O とは Input(入力) と Output(出力) の事 Input : プログラムが、プログラムの外から、情報を読み込む(Read) Output : プログラムが、プログラムの外へ、情報を書き出す(Write) [ポイント] 「外」はプログラムの置かれている環境で異る (i.e OS) 例 : 「あいさつ」をするとき日本とアメリカで異るの嫌(だから全て英語で.. それも困るが..) 環境の違いを吸収して、 プログラムは同じだが、実行結果は、 その環境において、適切に変化するようにする仕組みが欲しい その「仕組み」が標準ライブラリ => 標準ライブラリを利用すれば、 環境の違いを意識せずに、同じプログラムで(同じ機能を実現)できる 標準 I/O ライブラリの役割 異る環境でも、プログラムとしては、同じ方法で I/O を行うための仕組 環境の違いはライブラリが吸収 (挨拶は手を振るで OK) 標準 I/O ライブラリの機能 I/O する物 : 文字、文字列、数値(基本データ) I/O の相手先 : キーボード(I), ディスプレイ(O),ファイル(I/O) printf printf : 超高機能出力関数 print with format (書式付き出力) 単なる文字列出力関数ではなかった cf. printf ( "Hello, World\n" ); => 引数で指定された「文字列」を出力する 「書式('%' + 書式指示)」を指定する事により何(基本型+文字列)が出力できる printf ( 書式指定(の文字列) + 色々な型の値 ); => 基本型であれば、どんな型の値でも出力可能 !! printf の関数の引数には、 !! 色々な型の値を指定する事ができる !! !! 関数の実引数は、仮引数変数の型と同じ型の値と指定する !! !! => 関数の引数の型は、いつも同じ !! なぜ、このような(変な)事ができるかは.. !! この講義の最後あたりで、説明したい.. !! いまはしない.. printf ( "%d", 123 ); / printf ( "%f", 1.23 ); / printf ( "%c", 'a' ); / printf ( "%s", "abc" ); 文字列の中に出力(色々な値)を「埋め込む」事ができる int a=123; printf ( "int a=%d\n", a ); 複数のデータを一度に出力する事ができる int a=123; double b=1.23; printf ( "int a=%d, double b=%f\n", a, b ); 非常に高機能 printf の動作原理 後でちゃんと話すので、今回は我慢 !!
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20210924-01.c
/* * 20210924-01-QQQQ.c * * コンパイル : * cc -c 20210924-01-QQQQ.c * cc -o 20210924-01-QQQQ.exe 20210924-01-QQQQ.o * 実行 : * ./20210924-01-QQQQ.exe */ #include <stdio.h> /* * int quad_number ( int n ) * 奇数の和で二乗を計算する */ int quad_number ( int n ) { if ( n <= 0 ) { return 0; } else { /* 再帰呼出し */ /* n^2 = (n-1)^2 + (2n-1) */ /* ** この部分を完成させなさい */ } } /* * main */ int main ( void ) { /* sum = 1 + 3 + .. + 9 = 25 = 5^2 */ /* 整数型変数 sum の値を画面に出力 */ printf ( "1 から %d までの奇数の和は %d です。\n", 2 * 5 - 1, quad_number ( 5 ) ); return 0; }
$ ./20210924-01-QQQQ.exe 1 から 9 までの奇数の和は 25 です。 $
Download : 20210924-02.c
/* * TITLE * * 20210924-02-QQQQ.c * * コンパイル : * cc -c 20210924-02-QQQQ.c * cc -o 20210924-02-QQQQ.exe 20210924-02-QQQQ.o * 実行 : * ./20210924-02-QQQQ.exe */ #include <stdio.h> /* * main */ int main ( void ) { /* 整数型変数 odd の宣言とその初期化 ( 初期値は 1 を指定 ) */ int odd = 1; /* 整数型変数 sum の宣言とその初期化 ( 初期値は 0 を指定 ) */ int sum = 0; /* sum = 1 + 3 + .. + 9 = 25 = 5^2 */ /* odd の値が 9 以下の間は繰り返す */ while ( Q ) { /* sum に odd の値を「追加」する */ /* ** この部分を完成させなさい */ /* odd の値を次の奇数にする */ odd = odd + 2; } /* 整数型変数 sum の値を画面に出力 */ printf ( "1 から %d までの奇数の和は %d です。\n", 2 * 5 - 1, sum ); return 0; }
$ ./20210924-02-QQQQ.exe 1 から 9 までの奇数の和は 25 です。 $
Download : 20210924-03.c
/* * TITLE * * 20210924-03-QQQQ.c * * コンパイル : * cc -c 20210924-03-QQQQ.c * cc -o 20210924-03-QQQQ.exe 20210924-03-QQQQ.o * 実行 : * ./20210924-03-QQQQ.exe * * ファイルの中の数値の総和 */ #include <stdio.h> /* * main */ int main ( void ) { FILE *fp; /* 入力するファイルへのファイルポインタ値を持つ変数 */ int num; /* 入力された一つの整数値を持つ変数 */ int sum; /* 合計値 */ /* ファイル 「num.txt」を、読込モード 「r」で開く (open) */ /* ** この部分を完成させなさい */ if ( fp != NULL ) { /* ファイルのオープンができた */ sum = 0; /* 総和を 0 で初期化 */ while ( fscanf ( fp, "%d", &num ) > 0 ) { /* データを読み込む */ /* データがある限り.. */ /* sum に読み込んだ値 (num) を加える */ /* ** この部分を完成させなさい */ } printf ( "総和は %d です。\n", sum ); /* ファイルは必ずクローズする */ /* ** この部分を完成させなさい */ } else { /* エラーメッセージを出力 */ fprintf ( stderr, "ファイルがオープンできません\n" ); return -1; /* エラー終了 */ } return 0; }
$ ./20210924-03-QQQQ.exe 総和は 258 です。 $