/*
* 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 $