/*
* 20200710-02-QQQQ.c
* 入力された文字の字種を答える関数
*/
#include <stdio.h>
/*
* print_chractor_type ( char ch )
* 引数で指定された文字の種類 ( 大英文字、小英文字、数字、その他 )
* を判定し、その種類を表示する
*/
void print_chractor_type ( char ch ) {
/* まず、英大文字 ( 'A' <= ch <= 'Z' ) かどうかを判定 */
/* => これは二つの条件「'A' <= ch」と「ch <= 'Z'」の双方をチェック */
if ( 'A' <= ch ) { /* 'A' 以上で.. */
if ( ch <= 'Z' ) { /* 'Z' 以下なので.. */
/* 二つの条件「'A' <= ch」と「ch <= 'Z'」の双方が成立 */
putchar ( ch );
printf ( " は、英大文字です。\n" );
return; /* ここで関数を終了 ( 返り値はない ) */
} /* else {} */ /* else 節は省略 */
} /* else {} */ /* else 節は省略 */
/* まず、次は英小大かどうかを判定 */
if ( 'a' <= ch ) {
if ( ch <= 'z' ) {
/* .. */
return ;
}
}
/* 最後に、数字かどうかを判定 */
if ( '0' <= ch ) {
if ( ch <= '9' ) {
putchar ( ch );
printf ( " は、数字です。\n" );
return;
}
}
/* ここまで何かの条件が成立すれば return で終了している筈 */
/* ここにきたという事は、どの条件も成立していないので、「その他」と判定して良い */
putchar ( ch );
printf ( " は、その他です。\n" );
return; /* この return は不要だが、省略しない方が良い */
}
/*
* main
*/
int main ( void ) {
printf ( "キーボードから一文字入力すれば、文字の種類を表示します : " );
print_chractor_type ( getchar() );
return 0;
}
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
int main(void) {
printf ( "文字列、数値、文字をそれぞれ一行ずついれてください\n" );
s_print_string ( s_input_string() );
s_print_newline();
s_print_int ( s_input_int() );
s_print_newline();
s_print_char ( s_input_char() );
s_print_newline();
return 0;
}
#include <stdio.h>
#include "s_print.h"
int main(void) {
s_print_string ( " 13 % 5 = " );
s_print_int ( 13 % 5 );
s_print_newline();
s_print_string ( "-13 % 5 = " );
s_print_int ( -13 % 5 );
s_print_newline();
s_print_string ( " 13 % -5 = " );
s_print_int ( 13 % -5 );
s_print_newline();
s_print_string ( "-13 % -5 = " );
s_print_int ( -13 % -5 );
s_print_newline();
return 0;
}
#include <stdio.h>
/*
getchar() が値を返す ( 入力した文字を返す )
*/
int main(void) {
putchar ( getchar() ); /* 返ってきた値が式の中で利用できる */
putchar ( '\n' );
return 0;
}
#include <stdio.h>
/*
getchar() が返す値を式の中で利用する
*/
int main(void) {
putchar ( getchar() + 1 ); /* 返ってきた値が式の中で利用できる */
putchar ( '\n' );
return 0;
}
#include <stdio.h>
/*
getchar() が返す値を無視する事もできる
*/
int main(void) {
getchar(); /* void 型の関数と同じ扱いが可能 */
/* 返された値は無視される */
/* 命令 ( キーボードから文字を入力する ) は実行される */
/* 値を返す関数の呼び出しで、値に興味がない場合は
void 関数と同じように扱える */
/* 今回の場合は、「入力を待つ」という
振る舞い ( 副作用 : 関数の本来の目的は値を得る )
*/
return 0;
}
#include <stdio.h>
/*
入力された文字を一文字ずらして、出力する
*/
int main(void) {
/* main 関数の中で、すべてを行っている */
putchar ( getchar() + 1 );
putchar ( '\n' );
return 0;
}
#include <stdio.h>
/*
入力された文字を一文字ずらして、出力する
input-process-output
=> process の部分を関数として切り出す
機能 : 文字をずらす
*/
/*
char shift_char ( char ch )
引数で指定された『文字』の次の『文字』を返す
*/
char shift_char ( char ch ) {
/* 処理部分を関数の機能として切り出す */
/* => この関数の定義を別のソースに出して、再利用が可能 */
/* C 言語のプログラムでは main 関数が必須 */
/* => main 関数は再利用できない */
/* <= 再利用する場合は、関数として切り分ける */
return ch + 1; /* 一つ次の文字 */
}
int main(void) {
/* main 関数が I/O を担い、P は関数任せ */
putchar ( shift_char ( getchar() ) );
/* ^^^^^^^^^ 入力 */
/* ^^^^^^^^^^ 処理 */
/* ^^^^^^^ 出力 */
putchar ( '\n' );
return 0;
}
#include <stdio.h>
int main(void) {
printf ( "Hello, " ); /* 命令(関数呼び出し)を並べた : 順接 */
printf ( "World" ); /* 並べた順に(複数の)命令が実行される */
printf ( "\n" ); /* 単純な命令組み合わせて複雑な命令を作る */
/* 命令の実行順序が指定できる */
return 0;
}
#include <stdio.h>
/*
引数で指定された文字が、
'j' => 日本語で
'e' (など 'j' 以外) => 英語で
条件分岐
複数の命令のどちらか一方を実行したい場合
cf. 順接(単に命令を並べる)だと、両方実行される
*/
void print_hello ( char ch ) {
/* if 構文を利用して、条件分岐する */
if ( ch == 'j' /* 条件 */ ) { /* then 節 : 条件が成立した時の命令 */
printf ( "こんにちは、世界\n" ); /* 日本語 */
} else { /* else 節 : 条件が不成立の時 (成立以外) */
printf ( "Hello, World\n" ); /* 英語 */
}
}
int main(void) {
print_hello ( getchar() );
return 0;
}
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
/*
値段(整数値)を入力して、わかりましたと答える
その時に、値段が高い(10000以上は「高い」とする)場合だけ
「高い」
と文句を言う
*/
void print_pay ( int value ) {
s_print_int ( value );
s_print_string ( "円ですね。わかりました。払います。\n" );
if ( value > 10000 ) {
s_print_string ( "そんなに高いんですか ?\n" );
} else {
/* 何かをするのは、高い場合だけ.. */
}
}
int main(void) {
s_print_string ( "価格を整数値で入力してください : " );
print_pay ( s_input_int() );
return 0;
}
#include <stdio.h>
#include "s_print.h"
#include "s_input.h"
/*
値段(整数値)を入力して、わかりましたと答える
その時に、値段が高い(10000以上は「高い」とする)場合だけ
「高い」
と文句を言う
*/
void print_pay ( int value ) {
s_print_int ( value );
s_print_string ( "円ですね。わかりました。払います。\n" );
if ( value > 10000 ) {
s_print_string ( "そんなに高いんですか ?\n" );
} /* else 節の省略 */
}
int main(void) {
s_print_string ( "価格を整数値で入力してください : " );
print_pay ( s_input_int() );
return 0;
}
前回(2020/07/03)の内容
講義内容
「入力-処理-出力」
s_print.h/s_input.h の使い方
返値(かえりち)のある関数
s_print.h/s_input.h の使い方
2020/07/03 のページから、
c:\usr\c\include にダウロードする
使い方:
C 言語のソースファイルの先頭に次の二行を追加
#include "s_print.h"
=> s_print_AAAA ( AAAA : char/int/string )
=> char (文字), int (整数値), string (文字列) の出力が可能
#include "s_input.h"
=> s_input_AAAA ( AAAA : char/int/string )
=> char (文字), int (整数値), string (文字列) の入力が可能
コンパイル時に、追加のコンパイルオプション -I ~/c/include を追加
従来 : cc -c foobar.c
sを利用する場合 : cc -I ~/c/include -c foobar.c
=> リンク時は、従来と同じ
処理するデータの型が違うと、それを操作する関数が異なる
データを処理する時には、常にそのデータの「型」を意識する必要がある
文字型(char)、整数型(int)、文字列(char *)
標準関数の入出力 出力 入力
文字型 putchar getchar
文字列 printf 未習得
整数型 未習得 未習得
非標準(s_) 出力 入力
文字型 s_print_char s_input_char
文字列 s_print_string s_input_string
整数型 s_print_int s_input_int
整数型
C 言語で整数値(の一部)を扱う
int で整数型を表現する ( cf. char が文字型を表現 )
# int/char は型名
# 関数の仮引数変数の型宣言/関数の返り値の型
! C 言語で、直接扱える整数値の範囲が
! - 2^31 ? 2^31-1
! となっている。
! => 有限の数値しか扱えない
整数のリテラル ( 整[定]数値を表す表現 )
(十進数の)構文:[符号(-)] ( 0 または 0 から始まらない数字並び )
1, 123, -123, 0
整数の計算
四則 ( 和: +, 差: -, 積: *, 商: /, 余り: % ) の計算ができる
a / b は整数割り算になる
a / b = q .. r
r = a % b
a = b * q + r
r = a - b * q
13 % 5= 13 - ( 13 / 5 ) * 5
= 13 - 2 * 5
= 13 - 10
= 3
-13 % 5= -13 - ( -13 / 5 ) * 5
= -13 - ( -2 ) * 5
= -13 - ( -10)
= -3
13 % -5= 13 - ( 13 / -5 ) * -5
= 13 - ( -2 ) * -5
= 13 - ( 10)
= 3
-13 % -5= -13 - ( -13 / -5 ) * -5
= -13 - ( 2 ) * -5
= -13 - ( -10)
= -3
整数の比較 ( if 文で利用する )
等価 ( 等しい: ==, 等しくない: != )
# C 言語では、等値比較のために「==」を使い「=」は使わない
大小比較 ( 大なり: >, 小さいなり: <, 以下: <=, 以上: >= )
!! 文字もでも同じ
!! !! 内部的には、char 型の値(『文字』)は、
!! !! ASCII コード表に基づいて、小さな整数値 ( 0 ? 127 ) になっている
!! !! # 本当は、char 型に関しては ( -128 ? 127 )
整数の入出力
s_print_int()/s_input_int() を利用する
整数型の宣言 ( 引数/返り値 )
「int」を利用する
返値(かえりち)のある関数
関数の定義
=> 命令に名前をつけたもの
# プログラムは、命令を並べたもの
# 命令の並びに、名前を付けて、名前だけで呼び出せる
# => 関数
!!! 数学で「関数」といれば、「値を入れると値が返るもの」
!!! 「値の対応関係」が「関数の機能」
!!! C 言語の「関数」は、void と宣言され値を返さない
!!! cf. getchar() は「文字を返す関数」
!!! cf. main() は「整数値を返す関数」
C 言語でも、「値を返す『関数』」が定義できる
新しい点
関数名の前に void => 関数値の「型」(char,int,char *)
return 命令
return 式; => 式の値を計算し、関数の返り値とする
return 命令を実行すると、その時点で関数が終了する
# void 関数(値を返さない関数)
# でも、return; (式を書かない)が使えて、
# その場で、関数を終了させる機能が使える
その関数が値を返すので、その値を利用する「式」の中で利用できる
cf. void 関数は、関数呼び出しを文としてしか使えない
例 : void f(); => 「f()+1」かけない
int g(); => 「g()+1」として、関数の値を利用できる
!!! 関数の利用法
!!! void 関数 : f(); <= 関数 f を呼び出す
!!! 値を返す関数 : g(); <= void と同じにできる
!!! => 関数 g()が返した値は捨てられる
「入力-処理-出力」
プログラムの構成の仕方
言語を学ぶ => 意味を表すために、構文規則に沿って表現をする手段
「C 言語での表現方法」を学ぶ事が「ソフトウェア概論の目的」
=> 表現したい対象があって
その対象を「構成」する必要がある
上司が失敗した部下を叱る時
まず、失敗を指摘して叱る
次に、ほめて、やる気を出させる
逆にすると:
最初にほめて、て叱る
=> 落差がおおきくなって、より落ち込む
個々の表現だけでなく、表現の組み合わせが重要
プログラムの構成の仕方
複雑なものを簡単なものの組み合わせにしたい(分割統治)
どのように分割するか ?
分割の指標 : 「入力-処理-出力」
main データ入力
関数に引数としてデータを渡して処理
出力
a) 関数内
b) 値を返して、それ main で出力
b) =>
入出力を main にまとめて、
処理の部分を関数に集中させる事により、
プログラムの構成や意味がわかりやすくなる
[2020/07/10]
条件分岐 (if 構文)
条件分岐
複数の命令の内、
条件によって、
その複数の命令の内の、いずれか一つ
を実行する仕組み
cf.
順接 : 命令を並べる事により、
複数の命令を、並べた順に、それぞれ実行する仕組み
=> 記述量がふえると、実行量が増える
与えれた状況に併せて、適切な対応を選択する仕組み
プログラムの柔軟性を高める仕組み
if 構文 : 条件分岐を実現する C 言語での表現方法
構文 :
if ( 条件式 ) { then 節
条件が不成立時の文
} else { else 節
条件が成立時の文
}
条件式 : 真偽値(成立/不成立)を求める式
真 => 条件が成立
偽 => 条件が不成立 ( 成立しなかった )
例: !strcmp ( A, B ) => A,B が同じ文字列なら真
例: 整数型の値や文字型の値は「比較」ができる
==, != (等しい、等しくない)
<, >, <=, >= で、大小比較が可能
条件の成立時の文
条件が不成立時の文
: 複数の文(命令)が指定できる ( 空にする事も可能 )
意味
「条件」が
『成立』した時に「条件の成立時の文」
を、
そうでない時には、「条件が不成立時の文」
を
実行する
どちらか
一方だけ
が実行される
両方実行も両方不実行もなし
「if 『文』」ではなく、
「if 『構文』」である理由
「『文』を対象として、『何かをする表現』」
なので「メタ表現」
文は、データを対象とする表現
構文は、文を対象とする表現
cf. 「順接」も「順接構文」
if 構文 アラカルト
if 構文の基本 :
if ( C ) {
A
} else {
B
}
「基本」は「基本の組み合せだけで何でもできる」ので秀逸
色々な組み合せ方を学ぶ必要がある
else 節の省略
else 節 : if 構文の 「else { B }」の部分
B が空の時は、
「else {}」としても良い
が、
それを省略しても良い
基本:
if ( C ) {
A
} else {
}
else 節の省略の場合:
if ( C ) {
A
} /* else {} */ /* else 節を省略 */
then 節 ( { A } の所 ) は省略できない
基本:
if ( C ) {
} else {
B
}
できない:
if ( C )
else {
B
}
if 構文の「入れ子」
if 構文の文の中に if 構文をいれる
複数の条件の「条件の組み合せ」を
if 構文の組み合せで実現できる
例(複雑な条件) : ch が英大文字かどうか
'A' <= ch <= 'Z' [数学]
=> C 言語では、こう表現できません
# 別の表現があるが、後期に話す
例 :
if ( 'A' <= ch ) {
/* ここでは、 「'A' <= ch」が成立している */
if ( ch <= 'Z' ) {
/* ここでは「'A' <= ch」と「ch <= 'Z'」の両方が成立 */
/* ch が「英大文字」の時 */
} else {}
} else {}
else if 構文 (イデオム)
else 節の文全体が if 構文(入れ子)になっている場合
else 節のブレースを省略する
例: if ( C1 ) { A } else { if ( C2 ) { B } else { C } } => if ( C1 ) { A } else if ( C2 ) { B } else { C }
入れ子による、段の深化が防げる
一つのデータに対して、複数の条件の検査になっている
「表現」と「意味」の対応 (イデオム)
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20200710-01.c
/*
* 課題 CNAME-01
*
* CDATE FILENAME
*
* キーボードから一文字入力し、その文字によって異る国の挨拶をする
*/
#include <stdio.h>
/*
* hello ( char contry )
* char contry : 国を表す一文字
* j : 日本
* e : 英語
* c : 中国
* f : フランス語
* g : ドイツ語
*/
void hello ( char cmd ) {
switch ( cmd ) {
case 'j': /* 'j' の時は、日本語にする */
printf ( "こんにちは\n" );
break;
case 'e': /* 'e' の時は、英語にする */
/*
** この部分を完成させなさい
*/
break;
case 'c': /* 'c' の時は、中国語にする */
printf ( "ニイハオ\n" );
/*
** この部分を完成させなさい
*/
case 'f': /* 'f' の時は、フランス語にする */
printf ( "Bonjour\n" );
break;
/*
** この部分を完成させなさい
*/
printf ( "Guten tag\n" );
break;
default: /* どれでもなければ.. */
printf ( "???\n" );
break;
}
}
/*
* main
*/
int main( void )
{
printf ( "国を表す文字を入力してください\n" );
printf ( "\tj\t日本\n" );
printf ( "\te\t英語\n" );
printf ( "\tc\t中国\n" );
printf ( "\tf\tフランス\n" );
printf ( "\tg\tドイツ\n" );
hello ( getchar() ); /* getchar() で文字を入力し、それに対応する結果を出す */
return 0;
}
f
$ ./20200710-01-QQQQ.exe 国を表す文字を入力してください j 日本 e 英語 c 中国 f フランス g ドイツ Bonjour $
Download : 20200710-02.c
/*
* 20200710-02-QQQQ.c
* 入力された文字の字種を答える関数
*/
#include <stdio.h>
/*
* print_chractor_type ( char ch )
* 引数で指定された文字の種類 ( 大英文字、小英文字、数字、その他 )
* を判定し、その種類を表示する
*/
void print_chractor_type ( char ch ) {
/* まず、英大文字かどうかを判定 */
if ( 'A' <= ch ) { /* 'A' 以上で.. */
if ( ch <= 'Z' ) { /* 'Z' 以下なので.. */
putchar ( ch );
printf ( " は、英大文字です。\n" );
return; /* ここで関数を終了 ( 返り値はない ) */
} /* else {} */ /* else 節は省略 */
} /* else {} */ /* else 節は省略 */
/* まず、次は英小大かどうかを判定 */
if ( 'a' <= ch ) {
/*
** この部分を完成させなさい
*/
}
/* 最後に、数字かどうかを判定 */
if ( '0' <= ch ) {
if ( ch <= '9' ) {
putchar ( ch );
printf ( " は、数字です。\n" );
return;
}
}
/* ここまで何かの条件が成立すれば return で終了している筈 */
/* ここにきたという事は、どの条件も成立していないので、「その他」と判定して良い */
putchar ( ch );
printf ( " は、その他です。\n" );
return; /* この return は不要だが、省略しない方が良い */
}
/*
* main
*/
int main ( void ) {
printf ( "キーボードから一文字入力すれば、文字の種類を表示します : " );
print_chractor_type ( getchar() );
return 0;
}
v
$ ./20200710-02-QQQQ.exe キーボードから一文字入力すれば、文字の種類を表示します : v は、英子文字です。 $