/* * TITLE * * 2021/09/17 20210917-03-QQQQ.c * * scanf の書式指定 * */ #include <stdio.h> /* * */ /* * main */ int main( int argc, char *argv[] ) { int i; /* キーボードから入力された整数値を保持する整数型変数 */ double d; /* キーボードから入力された浮動小数点数値を保持する浮動小数点数型変数 */ printf ( "整数値(%%d)をキーボードから入力します : " ); /* プロンプト : 入力促進表示 */ scanf ( "%d", &i ); /* 整数値の入力なので、書式指定は %d を使う 入力したデータを保存する変数は整数型の変数 i で、 それを指定する場合は、変数名の前に「&」を付ける必要がある &i */ printf ( "入力された整数値は %d でした。\n", i ); printf ( "浮動小数点数値(%%lf)をキーボードから入力します : " ); scanf ( "%lf", &d ); /* 浮動小数点数値の入力なので、書式指定は %lf を使う 入力したデータを保存する変数は浮動小数点数型の変数 d で、 それを指定する場合は、変数名の前に「&」を付ける必要がある &d */ printf ( "入力された浮動小数点数値は %f でした。\n", d ); return 0; }
/* * 四角数 * @ 1 * * @@ 4 * @@ * * @@@ 9 * @@@ * @@@ * ... * * N^2 * * 二つの並んだ四角数の差 * * **@ 2 つ目の四角数と 3 つ目の四角数の差 * **@ +2 2 と 3 の和である 5 だけ差が * --- * @@@ +3 * k 個目四角数と、k+1個目四角数の差は * k + (k+1) = 2k+1 = 2(k+1)-1 ( k+1 個目の奇数 ) * => k 個目の四角数から k+1 個目の四角数を計算するには、 * k+1 個目の奇数を加えればよい * * 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) */ return quad_number ( n - 1 ) + 2*n - 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; }
/* * 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 sum = 1 + 3 + 5 + 7 + 9 今回は、5 個という個数が解っているので、 この形で明示的かけるが より一般には、k 個の奇数の和を求める事になる => ... が必要となるが、(数学の講義ではよいが..) プログラムではかけない => 同じ命令の繰り返しの形にしたい => sum = 0; sum <- 0 sum = sum + 1; sum <- 0 + 1 = 1 sum = sum + 3; sum <- 1 + 3 = 4 sum = sum + 5; sum <- 4 + 5 = 9 sum = sum + 7; sum <- 9 + 7 = 16 sum = sum + 9; sum <- 16 + 9 = 25 = 5^2 => sum = 0; odd = 1; sum = sum + odd; odd = 3; sum = sum + odd; odd = 5; sum = sum + odd; odd = 7; sum = sum + odd; odd = 9; sum = sum + odd; => sum = 0; odd = 1; sum = sum + odd; odd = odd + 2; sum = sum + odd; odd = odd + 2; sum = sum + odd; odd = odd + 2; sum = sum + odd; odd = odd + 2; sum = sum + odd; odd = odd + 2; => sum = 0; odd = 1; while ( odd <= 9 ) { sum = sum + odd; odd = odd + 2; } */ /* odd の値が 9 以下の間は繰り返す */ while ( odd <= 9 ) { /* sum に odd の値を「追加」する */ sum = sum + odd; /* odd の値を次の奇数にする */ odd = odd + 2; } /* 整数型変数 sum の値を画面に出力 */ printf ( "1 から %d までの奇数の和は %d です。\n", 2 * 5 - 1, sum ); return 0; }
#include <stdio.h> int main(void) { printf ( "変数 x の値は %d です。\n", 10 ); /* printf ( "Hello, World\n" ); */ printf ( "変数 %d と %d の和は %d です。\n", 10, 20, 10 + 20 ); return 0; }
#include <stdio.h> void func( int x ) { printf ( "x=%d\n", x ); } int main(void) { func ( 10 ); /* x <- 10 printf ( "x=%d\n", x ); => printf ( "x=%d\n", 10 ); => 「x=10\n」 */ func ( 20 ); return 0; }
#include <stdio.h> void func( int x ) { /* 仮引数変数 x には、実引数で指定された値が入っている */ printf ( "x=%d\n", x ); /* 実引数で指定された値 */ x = 100; /* 代入文 */ /* 変数 x には、代入文の右辺にある式の値(100)が割り当てられる */ /* 結果として、もともと変数 x が持っていた値は失われる */ /* 代入文の前後で、「環境(変数とその値の対の集まり)」が変わる */ /* => 時間(事前、事後)の概念 */ printf ( "x=%d\n", x ); /* x には、100 が代入されているので 100 が出力される */ } int main(void) { func ( 10 ); /* x <- 10 printf ( "x=%d\n", x ); x = 100; printf ( "x=%d\n", x ); => printf ( "x=%d\n", 10 ); x = 100; printf ( "x=%d\n", 100 ); => 「x=10\n」 「x=100\n」 */ func ( 20 ); return 0; }
#include <stdio.h> int main(void) { int x; /* int x, y; */ int y; /* 変数 x, y を整数型の変数として宣言 */ /* => このブロック内で有効な変数が作られる */ x = 1; y = 2; printf ( "%d + %d = %d\n", x, y, x+y ); return 0; }
#include <stdio.h> void func(void) { int x; /* 変数 x を宣言しているが、値は指定されていない */ /* この時点で、「どんな値をもつか」は「不定」 */ printf ( "x = %d\n", x ); } int main(void) { printf ( "最初の関数呼び出し\n" ); func(); printf ( "もう一度よびだしてみる\n" ); func(); return 0; }
#include <stdio.h> int main(void) { int vd; /* 入力させた 10 進数(digit)を保存するための変数(variable) */ int vc; scanf ( "%d", &vd ); /* %d : 10 進整数 */ vc = vd * 2; /* 変数 vc には vd を二倍した結果 */ printf ( "入力された値は %d です。二倍すると %d になる。\n", vd, vc ); return 0; }
#include <stdio.h> int main(void) { int vd; double vf; scanf ( "%d,%lf", &vd, &vf ); /* double 値の入力の場合は、 %lf になる */ printf ( "入力された整数値は %d で、浮動小数点数値は %f\n", vd, vf ); /* double 値の出力は %f だけでよい */ /* 書式は 1. 入力の形式を指定する 2. 入力された後に、どの型に変更するか */ return 0; }
#include <stdio.h> int main(void) { int vd; double vf; scanf ( "%d", &vd ); scanf ( "%lf", &vf ); /* scanf の書式指定は、 変数毎に、その型だけを指定して、 他の文字は一切入れない形を推奨 */ /* => scanf の眷属 キーボードからの入力(普通、人間がやる)ではない ものからの入力 文字列から(中身を分解して..)値を取りだす sscanf ファイルから入力を行う fscanf => これらの書式しては、複雑なものが、すごく役に立つ */ printf ( "入力された整数値は %d で、浮動小数点数値は %f\n", vd, vf ); /* double 値の出力は %f だけでよい */ /* 書式は 1. 入力の形式を指定する 2. 入力された後に、どの型に変更するか */ return 0; }
#include <stdio.h> /* 目的 "abc\n" を 10 回表示したい */ int main(void) { printf ( "abc\n" ); printf ( "abc\n" ); printf ( "abc\n" ); printf ( "abc\n" ); printf ( "abc\n" ); printf ( "abc\n" ); printf ( "abc\n" ); printf ( "abc\n" ); printf ( "abc\n" ); printf ( "abc\n" ); return 0; }
#include <stdio.h> /* 目的 "abc\n" を 10 回表示したい 再帰 */ void tentimes(void) { printf ( "abc\n" ); tentimes(); /* 関数の本体の中で、自分自身を呼び出す */ } int main(void) { tentimes(); return 0; }
#include <stdio.h> /* 目的 "abc\n" を 10 回表示したい 再帰 */ void tentimes(int count) { /* count : 何度出力したかの記録 */ if ( count == 10 ) { /* 必要なだけ出力されなら */ /* 終わりにする */ /* なにもせずに終了 */ } else { printf ( "abc\n" ); /* まだ、おわっていないので、出力 */ tentimes( count + 1 ); /* 出力したという回数 +1 する */ } } int main(void) { tentimes( 0 ); /* 引数は、出力した数を表す 最初は 0 回数 */ return 0; }
#include <stdio.h> /* 目的 "abc\n" を 10 回表示したい while 構文 */ void tentimes(int count) { /* count : 何度出力したかの記録 */ if ( count == 10 ) { /* 必要なだけ出力されなら */ /* 終わりにする */ /* なにもせずに終了 */ } else { tentimes( count + 1 ); /* 出力したという回数 +1 する */ } } int main(void) { int count; /* 繰り返す個数 */ count = 0; /* 初期化 */ while ( count < 10 ) { printf ( "abc\n" ); count = count + 1; /* 今までの count の値を利用して、新しい count の値を計算し、代入する */ /* 代入文の 左辺 : 変数名 ( 代入の対象となる変数名 ) 右辺 : 式 ( 代入する値を計算する式 ) 式の中に、左辺の変数名が現れていても、 左辺の計算をする時は、まだ、代入が行われていないので、 その変数の値は、代入前の値となる => 変数の値の可能 */ } return 0; }
#include <stdio.h> int main(void) { while ( 2 > 1 ) { /* この条件式は常に成立 */ printf ( "abc\n" ); } return 0; }
#include <stdio.h> int main(void) { int d = 2; while ( d > 1 ) { /* この条件式は常に成立 */ printf ( "abc\n" ); /* 変数を含むが、変数の値が変更されない */ } return 0; }
#include <stdio.h> /* while 構文のイデオム N 回繰り返す */ int main(void) { int counter; /* 繰り返し回数を記録する整数型の変数を用意する */ counter = 0; /* while 構文の直前に 0 を代入する */ while ( counter < 10 ) { /* 条件式 : 繰り返す回数未満 */ printf ( "abc\n" ); /* 繰り返したい命令 */ counter = counter + 1; /* 回数を 1 増やす */ } return 0; }
#include <stdio.h> int main( int argc, char *argv[] ) { /* main 関数から、コマンドライン引数を参照する仕組み argc (最初の引数) : コマンドライン引数の個数 + 1 argv (二つ目の引数) : i 番目の引数が argv[i] で参照できるようになっているもの */ printf ( "引数の個数は %d です。\n", argc - 1 ); printf ( "最初の引数は %s です。\n", argv[1] ); printf ( "二つ目の引数は %s です。\n", argv[2] ); return 0; }
#include <stdio.h> int main( int argc, char *argv[] ) { /* main 関数から、コマンドライン引数を参照する仕組み argc (最初の引数) : コマンドライン引数の個数 + 1 argv (二つ目の引数) : i 番目の引数が argv[i] で参照できるようになっているもの */ int na; printf ( "引数の個数は %d です。\n", argc - 1 ); na = 1; while ( na < argc ) { printf ( "%d 目の引数は %s です。\n", na, argv[na] ); na = na + 1; } return 0; }
2021/10/01 09:00- ソフトウェア概論 B 代入 局所変数の宣言 変数への値の代入 (代入文) 標準 Iinput/Ouput printf : 書式つき出力 == printf : 書式つき出力 print with format ^^^^^ ^ printf 出力するとき : print (write) をつかう C 言語だけ printf printf ( 書式, それに埋め込まれるデータ列.. ) 書式 : 基本文字列 文字列内に出力形式を指定する文字列(書式指定)が含まれている 書式指定 : % から始まる 例 printf ( "変数 x の値は %d です\n", 10 ) 書式指定: % + 一文字 : 色々なデータの出力が可能 d (digit) : 10 進数整数 f (float) : 浮動小数点数 c (char) : 文字 s (string) : 文字列 !! printf が高機能になっている仕組み !! 書式指定の部分を解釈して、適切に出力を行う仕組み !! 「解釈する」 !! 指定されたデータに対し、 !! その表現にたいする適切なふるまいをするようになっている !! !! 通常の関数は、引数は、それ単体で意味があるとあつかう !! !! add( 1, 2 ) !! !! 1 + 2 <= 1, 2 単体のデータ ( 内部構造はかんがえない ) !! !! printf ( ".. %d .. %c .. ", .. ) !! !! ^^^^^^^^^^^^^^^^^ 文字列の中、さらに部分的な情報があって、それを分解して、処理している !! !! printf の原理 ( 色々な知識が必要 ) は、最後の方 !! !! => 文字列を「解釈」して色々な事をする !! !! => 高機能化につながっている 代入 構文 : 変数名 = 式; 変数名で指定される変数に対し、式の値を割り当てる 変数の値が、代入を行った後は、 その割り当てられた値になる 局所変数(auto 変数/自動変数)とその宣言 局所変数 : それが宣言されているブロック内だけで有効な変数 ブロック : プログラム中の 「{」から「}」の間 !! すべてのブロックの外でも有効な変数 !! => 大域変数(グローバル変数) 仮引数変数は、関数の本体(となるブロック)内で有効な局所変数となる 局所変数宣言 => ブロックの先頭で、変数宣言をする事ができる 変数の型名 変数名(, 変数名.. ) => そのブロック内だけで有効な局所変数を宣言できる cf. 仮引数変数も、局所変数の一種 1. 宣言する場所が違う 2. 仮引数変数は、実引数の値を最初(有効になった[ブロックに入った]時点)から持っている => 局所変数宣言で宣言された変数は、(値をはじめからもっているが、)その値は不定(ゴミが入っている) 普通の局所変数の場合は、利用するまえに、 最初の代入(変数の初期化)を済ませてから、利用する 「変数の初期化忘れ問題」 代入をつかいたい 変数が必要 局所変数宣言をする 初期化を忘れると、トラブル !! 関数の引数は、安全な変数の宣言と代入 == scanf 書式つき入力関数 cf. printf : 書式付出力関数 入力 : データをプログラムの外 ( キーボードだとか.. ファイル.. ) から プログラム内に取り込む cf. getchar() : キーボードから一文字入力する => 入力されたデータ(文字コード)は、 関数値として参照可能 scanf では、入力されたデータ(文字列)が、 適切なデータ型に変換され、変数に代入される 入力されたデータ(値)を収める変数は、 scanf の書式の後に、指定するが、 その時に、変数名の前に「&」を付ける必要がある => この「&」の意味と、付ける理由は、今日は話さない !! 「ポインター」という概念と関係 scanf の書式指定がされると、 入力をする時に、その書式に合わせて、入力しないと、 大変(期待したことと異なる結果になる事が多い) => scanf を使うなら書式指定は、 最小限度(一つの変数の型指定だけする)のがおすすめ プログラムの基本パターン input-process-output scanf で変数に入力した値を代入し 代入文を利用して、変数の値を使った計算を行い、 計算結果を別の変数代入 printf で、変数に保存されている計算結果を出力 == 標準入出力の話 => 次回に回す == while 構文 命令を繰り返すための構文 形式 while ( 「条件」 ) { 「繰り返す命令」 } => 「条件」が成立している限り、「繰り返す命令」を繰り返す <<while 構文>> | +-----> | | | | 条件のチェック -----+ | | 成立 | 不成立 | v | | 繰り返す命令を実行 | | | | +-------+ | | +<--------------+ | v 終わり while 構文の「条件式」は、同じもの もし、「条件式」の中に「変数が含まれていない」か あるいは、「含まれていても変化しない」場合 => 無限に繰り返す事になる while 構文の命令を有限回で止めるには、 条件式の中に、変数を含め、 繰り返す命令の中で、 (いつかは..) その変数の値を変更する必要がある => 「代入文」が必須 == コマンドライン引数(what) 「実行ファイル (*.exe)」を実行する時に、後ろに引数(コマンドライン引数)をつける事ができる 例 : ./p-001.exe foo bar argc -> 3 このコマンドライン引数は、「文字列」として 「main 関数」に渡される # コマンドライン引数は、間に空白文字が含まれている場合は、 # その空白文字を削って、引数をそこで、分割して、複数の文字列として扱う いままで main(void) => 引数は「void」(引数がない関数) main 関数の引数 ( int argc, char *argv[] ) main の最初の二つの引数 一つ目 : コマンドライン引数の個数 + 1 二つ目 : コマンドライン引数自身の文字列のリスト(配列)になっていて、 i 番目の引数の文字列は argv[i] を指定する事により、取り出せる コマンドライン引数が参照できる argc : コマンドライン引数の個数 + 1 argv[n] : n 番目のコマンドライン引数の文字列 ( argv[0] は、実行ファイル名が入っている ) コマンドライン引数の効用 入力以外に、プログラムに情報を渡す仕組みの一つ 実行前に値を指定する必要がある ( 指定できる ) 入力先となるファイル名を示す ( メタ的 / パラメータ的利用 ) 文字列から数値への変換を行う関数 atoi ( ASCII to int : 文字列から整数値 ) / atof ( ASCII to float : 文字列から実数値 )
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20211001-01.c
/* * TITLE * * 20211001-01-QQQQ.c * * コンパイル : * cc -c 20211001-01-QQQQ.c * cc -o 20211001-01-QQQQ.exe 20211001-01-QQQQ.o * 実行 : * ./20211001-01-QQQQ.exe * * コマンドラインで指定された整数値の総和を計算する */ #include <stdio.h> /* * main */ int main ( int argc, char *argv[] ) { int sum = 0; /* 総和の値を保持する変数 */ int n = 1; /* 現在参照している引数の番号 */ while ( n < argc ) { /* 引数のある限り */ /* その引数の文字列を整数値に変換し、加える */ /* ** この部分を完成させなさい */ /* 次の引数を参照するために、参照する番号を増やす */ n = n + 1; } /* 結果を出力 */ printf ( "引数で指定された整数値並びの総和は %d です。\n", sum ); return 0; }
$ ./20201002-01-QQQQ.exe 123 456 789 引数で指定された整数値並びの総和は 1368 です。 $
Download : 20211001-02.c
/* * TITLE * * 20211001-02-QQQQ.c * * コンパイル : * cc -c 20211001-02-QQQQ.c * cc -o 20211001-02-QQQQ.exe 20211001-02-QQQQ.o * 実行 : * ./20211001-02-QQQQ.exe * * コマンドラインでファイル名を指定して、画面に表示する */ #include <stdio.h> /* * main */ int main ( int argc, char *argv[] ) { FILE *fp; int ch; /* 入力される文字コード */ /* 引数が指定されているかどうかを判定 */ if ( argc < 1 ) { /* 引数がない */ fprintf ( stderr, "引数を指定してください\n" ); return -1; } /* 最初の引数をファイル名として open (二つ目以後は無視) */ /* ** この部分を完成させなさい */ /* ファイルが open できたかどうかを判定 */ if ( fp == NULL ) { fprintf ( stderr, "ファイル(%s)の open に失敗しました\n", argv[1] ); return -2; } /* 最初の一文字を読み込む */ /* ** この部分を完成させなさい */ while ( ch != EOF ) { /* EOF は、ファイルの終りを表す整数値 */ /* 画面に入力した文字を出力 */ putchar ( ch ); /* 次の一文字を読み込む */ ch = fgetc ( fp ); } fclose ( fp ); return 0; /* 正常終了 */ }
$ ./20211001-02-QQQQ.exe $