Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
第 1回
今日の課題
授業のガイダンス.簡単な Cのプログラムを実行してみる.本日のミニプログラム
本日のミニプログラム
#include <stdio.h>
int main(void)
{
printf("Hello");
}
まずはシラバスを見てみよう
担当教員:
単位について:
教科書は,このウェブ上のテキストです.このテキストで,Cプログラミングの基礎(配列や関数の使い
方まで)を学習することができます.この講義の内容だけ理解すればよい人は,このテキストだけで十
分です.
このテキストだけでは物足りない人は,市販の参考書も数多くありますので,ざっと内容を見て,自分
にあった参考書を選ぶと良いでしょう.
将来ソフト系に進むのであれば,この講義が終わったあと,自分に合ったできるだけ詳しい本を選んで
持っておくと良いでしょう.
講義に関する注意
出欠の方法(口頭で説明)
なるべく多くの人を指名して,質問や意見を聞きたいと思います.指名されたときに,返事をしなけれ
ば欠席とみなします.
講義中は,スマホなどの使用は禁止.ノートを持参してください.
無断で教室を抜け出すことは禁止します.(トイレの場合も申告すること)
説明中はタイプしないこと.
使用後は必ずシャットダウンし,ログオフのまま立ち去らないこと.
講義では,terapadと Cygwinを使います.テキスト,terapad,Cygwinを PC 画面に配置してください.
Cのプログラムの作成と実行
(1) C言語のプログラムを編集する(xx.c)
terapadを開く
プログラムを入力する.入力は全角文字ではなく半角英数で入力してください.
(キーボードの入力モードをひらがなではなく直接入力に切り替えてください.)
名前をつけて(例えば test0410a.c)z:フォルダに保存する.
ファイル名が,**.txtとならないよう注意.z:フォルダに Cと書かれたアイコンが出来ればよい.
再度編集する場合には,Cのプログラムのアイコンを terapadにドラッグしてください.
(2) Cygwin上でコンパイルおよび実行する
Cygwin のアイコンを Wクリックする.
コンパイルして(gcc xx.c)実行形式ファイル(a.exe)を作成する.
バグがある場合には,エラーメッセージが出る.
Cygwin 上で実行形式ファイルを実行させる(./a.exe).
./a.exeとタイプするとプログラムが動く. (./ の意味は?)
例題 1
C言語では,スペース,タブ,改行は適当に入れて構いません.プログラムの内部が見やすいよう右にず
れていますが,Tabキーまたはスペースキーを使ってずらします.ずらさなくても構いません.コンパイ
ラが全角スペースを認識できませんので,全角スペースを入れるとプログラムが動きません.
#include <stdio.h>
int main(void)
{
printf("ABC");
}
(注)プログラムで全角文字が使えるのは,コメントや文字列のみで,それ以外の場所に全角文字を入
れるとエラーがでます.
C言語のプログラムは,main関数の中に処理の記述を入れることで動きます.
main(){ }
Cygwinで知っておいた方が良いコマンド
↑:前の命令を呼び出す
↓:後の命令を呼び出す
ls:ファイルのリストを出す
ls –l:ファイルのリストを詳細情報付で出す
その他知っておいた方がよいコマンド
(mv,cp,rm,pwd,mkdir,cd,cat,vi)
cygwin は一度開いたら授業の間ずっと開きっぱなしで構いません.
PCの画面上にテキスト,terapad,Cygwinを見やすいように並べてください.
練習 ABCを My name is XXXX. に置き換えてみましょう.
ABCを My name \nis XXXX. に置き換えてみましょう.
例題 2
#include <stdio.h>
int main(void)
{
int i,j=0;
for(i=1;i<=10;i++)j=j+i;
printf("%d\n",j);
}
思ったとおりに動かない場合
ファイルを右クリックし「編集」で,プログラムを確認し修正し,上書き保存する.
Cygwinで再度コンパイルして実行する.
例題 3
#include <stdio.h>
#include <math.h>
int main(void)
{
int i;
float x;
for(i=0;i<10;i++){
x=sqrt(1.0*i);
printf("%d %f\n",i,x);}
}
例題 4
/*鶴亀算,足は合計 26本,全部で 10匹*/
#include <stdio.h>
int main(void)
{
int turu,kame,hiki,ashi;
hiki=10;
ashi=26;
kame=(ashi-hiki*2)/2;
turu=hiki-kame;
printf("鶴は%d匹\n",turu);
printf("亀は%d匹\n",kame);
}
例題 5
#include <stdio.h>
int main(void)
{
char a;
a='A';
printf("%c\n",a);
putchar('B');
putchar('B'+5);
printf ("\n");
puts("xyz");
printf ("\n");
puts("abc");
}
本日のまとめ
Cのプログラムを実行する手順を学習した.
第 2回
今日の課題
printf()と文字列の表示.コメント.特殊文字の表示.実行結果のファイルへの出力方法.実行結果の
送信メールへの取込み方法.
本日のミニプログラム
#include <stdio.h>
int main(void)
{
printf("\tTab"); /*Tab*/
}
作成ファイルの整理
作成ファイルには以下の例のように,授業の回数や演習の日付で系統的な名前をつけておきましょう.
例 2007年 5月 11日のプログラム 0511a.c 0511b.c 0511c.c
printf()と文字列の表示
printf("hello");は helloという文字を画面に表示させます.
ダブルクオーテーション"で囲まれた文字の集まりを文字列と言います.printf()文ではカッコの中の文
字列を画面に出力(表示)します.ダブルクオーテーションは表示されません.
例題
次のプログラムを実行させましょう.
/*test program*/
#include <stdio.h>
int main(void)
{
printf("2014/04/23\n");
printf("10t8099A\tSuzuki Ichiro\n");
}
プログラムは,半角スペースや Tabを使って見やすいようにずらしてください.(インデント)
実行結果のファイルへの出力方法と表示のコピー
リダイレクトという機能を使うと結果が画面に表示されるのではなく,新しいファイルができ出力結果
が内容として書き込まれます.
./a.exe>output.txt
(実行形式ファイル>出力ファイル)
.txtはテキストファイルを示す拡張子です.
テキストファイルはワードパッドで開くことができます.
また Cygwin では範囲を指定し,編集>コピーで,指定した範囲をコピーし,ワードやメールに貼り付け
ることができます.
コメント
プログラム中で/*から始まって*/で終わるまでの部分は,実行されません.(コメント)
また文の//より右側はコメントとして実行されません.
(注意)全角文字はコメント(/*...*/)文字列("...")以外では使えません.まず全角以外の編集
をしてから,最後に全角の部分を追加するのが良いでしょう.
拡張表記
printf("")でダブルクオーテーションに囲まれた中に,以下の記述を入れると,改行などの表示が出来
ます.
\n:改行 \t:タブ \\:「\」円記号
\0:ヌル文字 \":「"」ダブルクォテーション
注 ヌル文字は,文字列の終端であることを表す特殊な文字で表示されません.
\n や\t のように/の逆の文字(バックスラッシュ)を使っている本もありますが,実際には半角の円
記号"\"を使ってください.
練習問題 1 例題で文字列から\nを除いて実行してみましょう.
練習問題 2 文字列の途中に\0を入れて実行してみましょう.
例題
#include <stdio.h>
int main(void)
{
printf(
"hello, world");
}
C言語では 1つの文を複数行に分けても実行されます.
例題
#include <stdio.h>
int main(void)
{
printf("hello");
printf("hello");
printf("hello");
}
printf()文を 3 つに分けても,画面には改行されずつながって表示されます.改行を行う場合には,最
後に\n を入れましょう.
例題
#include <stdio.h>
int main(void)
{
printf("hello\n");printf("hello\n");printf("hello\n");
}
C言語では 1つの行に複数の文を書くこともできます.
例題
#include <stdio.h>
int main(void)
{
printf("C言語では\"\\n\"は改行をあらわします\n");
printf("\\nがないと");
printf("改行されません");
}
Cygwin では日本語を表示する場合に,文字が化けることがあります.
第 3回
今日の課題
変数と型,代入,scanf()で値の読み込み,printf()で値の表示
本日のミニプログラム
#include <stdio.h>
int main(void)
{
int x,y; /*変数の宣言*/
scanf("%d",&x); /*入力*/
y=x*2; /*代入*/
printf("%d",y); /*出力*/
}
例題 3-1
#include <stdio.h>
int main(void)
{
int math,phys,wa,heikin;
math=60;
phys=70;
wa=math+phys;
heikin=wa/2;
printf("点数の和=%d\n",wa);
printf("平均=%d\n",heikin);
}
math,phys,wa,heikinは整数型の変数です.変数の名前は自分で決められます.
math=60;は変数 mathに 60を代入します.
wa=math+phys;は変数 mathの値と変数 physの値を足した値を変数 waに代入します.
heikin=wa/2;は変数 waの値を 2で割った値を変数 heikinに代入します.
変数の宣言と型について
C言語では,整数や実数など色々な種類の値(数値)を扱います.値の種類を型と呼びます.
この講義では int(整数),char(文字),float(単精度実数),double(倍精度実数)の型を使います.
実数は主に float型を使います.
C言語では,プログラムの中で値を保存するのに変数を使います.最初に使いたい変数がどのような型(整
数,実数など)なのかを決めておく必要があります.これを変数の宣言と呼びます.次のように宣言し
ます.
型の種類 変数名,変数名,・・・;
例
int i,j; /*iと j は整数型の変数である*/
double x; /*xは倍精度の実数である */
変数の宣言と同時に,変数に値を代入することもできます.
int k=3; /*kは整数型の変数である また kに 3を代入する*/
通常 i,j,k,m,nなどの変数は,整数型の変数として使うことが多いです.
代入
変数名=値または式;
とすると,右側の値や式が左側の変数に代入されます.a,b,cを変数とすると
a=b+c;
は正しいですが,
a+b=c;
とするとエラーになります.
代入はイコールとは違うので気をつけましょう.
練習問題 3-1
例題 3-1で変数の宣言と,変数への値の代入を同時に行うプログラムに書き替えよう.
一歩進んで
例題 3-1で赤字の部分を 1行に置き換えることができます.
heikin=(wa=(math=60)+(phys=70))/2;
実行して,命令の意味について考えてみよう.
関数 printf()について
printf()を使って文字列を表示する方法はすでに習いました.printf()を使うと,文字列だけでなく値
(数値)を表示できます.
%dは整数型の書式指定子と呼ばれ,後に続く整数の値が%d に置き換わって表示されます.
例
例題 3-2
#include <stdio.h>
int main(void)
{
int a,b,c;
printf("Aの点数?\n");
scanf("%d",&a);
printf("%dたす%dは%dです",1,2,3);
printf("Bの点数?\n");
scanf("%d",&b);
printf("Cの点数?\n");
scanf("%d",&c);
printf("A,B,Cの和=%d\n",a+b+c);
printf("平均=%d\n",(a+b+c)/3);
}
3,4,5と入力した場合と 3,4,4と入力した場合の結果を比べてみましょう.
関数 scanf()について
scanf("%d",&x)の文では,整数型の書式指定子%d が使われているので,キーボードに入力した値が,整
数として変数 xに代入されます.
scanf()では変数の先頭に&(アンパッサンド)が付くことに気をつけてください.また変数の型と書式
指定子%○が一致しなくてはいけません.
例題 3-3
#include <stdio.h>
int main(void)
{
float a,b,h,s;
printf("台形の面積を求めます\n");
printf("上底?\n");
scanf("%f",&a);
printf("下底?\n");
scanf("%f",&b);
printf("高さ?\n");
scanf("%f",&h);
s=(a+b)*h/2.0;
printf("台形の面積=%f\n",s);
}
実数の入力と表示
float型の書式指定子は%fです.
scanf("%f",&a)では,実数型の書式指定子%f が使われているので,キーボードに入力した値が,実数と
して変数 aに代入されます.
float型で printf(),scanf()を使う場合には,%dではなく,%fになることに注意しましょう.
printf("台形の面積=%f\n",s);のように,実数を表示することができます.double型の書式指定子は%lf
(エルエフ)です.
大文字と小文字について
プログラムの中で同じアルファベットでも大文字と小文字は別の文字として扱われます.また scanf,
include,int などの C言語で決められた単語で大文字と小文字を間違えるとエラーになります.
次のプログラムでは変数 aと Aが別の変数として扱われています.
#include <stdio.h>
int main(void)
{
int a,A;
scanf("%d",&a);
A=a*3;
printf("%d",A);
}
例題 3-4
#include <stdio.h>
int main(void)
{
int a,b,c;
float d;
scanf("%d",&a);
scanf("%d",&b);
c=(a+b)/2;
d=(a+b)/2.0;
printf("%d\n",c);
printf("%f\n",d);
}
3と 4を代入してみましょう.
演算による結果
整数同士,実数同士の演算では,結果の値の型は変わりません.整数同士の乗除では小数点以下が切り
捨てられます.整数と実数が混ざった演算では,結果の型は実数になります.
変数の型と書式指定子のまとめ
型名 種類 書式指定子
int 整数型 %d integerの略
char 文字型 %c characterの略.-128 から 127
までの整数(文字)を扱う.
float 実数型 %f
double 倍精度実数型 %lf
練習問題
実数型の値を入力し 1000倍の値を出力するプログラムを作りましょう.
第 4回
今日の課題
文字型変数,文字の入出力 getchar(),putchar(),色々な演算(z=5%2,x*=3,i++など)
本日のミニプログラム
#include <stdio.h>
int main(void)
{
int x=2;
x+=3;
printf("%d",x);
}
整数と実数が混ざった計算の注意
整数と実数が混ざった計算では,頭で考えたとおりの結果にならないことがあるので注意しましょう.
例えば
1/9.0=0.1111111
0.1111111*9=0.9999999 この値を整数に変換すると 0になる!
次の例でも結果が 0になることがあります.
int i;
float x;
x=1/100.0;
i=x*100.0;
printf("%d\n",i);
例題 4-1
/*小文字を大文字に変換する */
#include <stdio.h>
int main(void)
{
char moji;
printf("小文字");
scanf("%c",&moji);
moji=moji-'a'+'A';
printf("%c\n",moji);
}
文字と ASCIIコード
'a','@','6'のようにシングルクオーテーション(')で囲まれたものは文字(文字型の値)です.文字
は計算機の中では数値として扱われるので,足し算や引き算が出来ます.文字と数値との関係を決めた
代表的なものに,ASCII(アスキーと呼ぶ)コードがあります.付録に,ASCIIコードを示します.
"abc","文字"のようにダブルクオーテーション(")で囲まれたものは文字列です.'a'と"a"は違うもの
なので気をつけてください.
文字型の変数と文字の入出力
charは文字型の変数を宣言します.文字型の変数は整数として扱うことができます.上の例題で「char」
を「int」に変えて実行してみましょう.scanf()や printf()で文字を入出力する場合には,%cの書式指
定子を使います.文字の入出力には,getchar()と putchar()も使えます.
練習問題 4-1
例題では文字'b'がどのように文字'B'に変換されるかを考えて,今度は大文字を読み取り小文字に変換
するプログラムに修正してください.
練習問題 4-2
moji=getchar();で 1 文字を変数 moji に読み込むことができます.putchar(moji);で変数 moji の値(1
文字)を表示することができます.
getchar()と putchar()を使って例題 4-1を書きかえてください.
練習問題 4-3
次のプログラムを実行しましょう.
(注)for(i=0;i<128;i++)...は変数 i の値を 0 から 127 まで繰り返すという処理ですが,詳しくは後
ほど勉強します.
#include <stdio.h>
int main(void)
{
int i;
for(i=0;i<128;i++){
printf("%d\t",i);
putchar(i);
putchar('\n');
}
}
例題 4-2
#include <stdio.h>
int main(void)
{
int x;
float y;
x=10;
x++;
printf("%d\n",x);
x=20;
x%=7;
printf("%d\n",x);
y=8.0;
y/=2.0;
printf("%f\n",y);
y/=2.0;
printf("%f\n",y);
y/=2.0;
printf("%f\n",y);
}
剰余算
%は整数を整数で割ったときの余りを求める演算です.(x=20%6;)書式指定子の%とは違うので気をつけ
ましょう.
自己代入型演算子,インクリメント,デクリメント
変数に演算処理を行いその結果を同じ変数に代入するものを自己代入型演算子とよびます.また変数の
値を一つ増やすのがインクリメント,一つ減らすのがデクリメントです.
加 x=x+a; x+=a; (x++ x=x+1;)
減 x=x-a; x-=a; (x-- x=x-1;)
乗 x=x*a; x*=a;
除 x=x/a; x/=a;
剰余 x=x%a; x%=a;
練習問題 4-4
例題 4-1を自己代入型演算子を使ったプログラムに書き換えましょう.
一歩進んで
インクリメント,デクリメントでは,演算子が変数の前にある書き方(前置型)と,変数の後ろにある書
き方(後置型)があります.i++ ++i j=i++ j=++i
前置型は全体の式の計算(代入)より先に,インクリメント,デクリメントを行います.
ASCIIコード 10進数と 16進数の対応についてもよく理解しておきましょう.
文字 10 進 16 進 文字 10 進 16 進 文字 10 進 16 進 文字 10 進 16 進
NUL 0 0x00 SP 32 0x20 @ 64 0x40 ` 96 0x60
SOH 1 0x01 ! 33 0x21 A 65 0x41 a 97 0x61
STX 2 0x02 " 34 0x22 B 66 0x42 b 98 0x62
ETX 3 0x03 # 35 0x23 C 67 0x43 c 99 0x63
EOT 4 0x04 $ 36 0x24 D 68 0x44 d 100 0x64
ENQ 5 0x05 % 37 0x25 E 69 0x45 e 101 0x65
ACK 6 0x06 & 38 0x26 F 70 0x46 f 102 0x66
BEL 7 0x07 ' 39 0x27 G 71 0x47 g 103 0x67
BS 8 0x08 ( 40 0x28 H 72 0x48 h 104 0x68
HT 9 0x09 ) 41 0x29 I 73 0x49 i 105 0x69
NL* 10 0x0a * 42 0x2a J 74 0x4a j 106 0x6a
VT 11 0x0b + 43 0x2b K 75 0x4b k 107 0x6b
NP 12 0x0c , 44 0x2c L 76 0x4c l 108 0x6c
CR 13 0x0d - 45 0x2d M 77 0x4d m 109 0x6d
SO 14 0x0e . 46 0x2e N 78 0x4e n 110 0x6e
SI 15 0x0f / 47 0x2f O 79 0x4f o 111 0x6f
DLE 16 0x10 0 48 0x30 P 80 0x50 p 112 0x70
DC1 17 0x11 1 49 0x31 Q 81 0x51 q 113 0x71
DC2 18 0x12 2 50 0x32 R 82 0x52 r 114 0x72
DC3 19 0x13 3 51 0x33 S 83 0x53 s 115 0x73
DC4 20 0x14 4 52 0x34 T 84 0x54 t 116 0x74
NAK 21 0x15 5 53 0x35 U 85 0x55 u 117 0x75
SYN 22 0x16 6 54 0x36 V 86 0x56 v 118 0x76
ETB 23 0x17 7 55 0x37 W 87 0x57 w 119 0x77
CAN 24 0x18 8 56 0x38 X 88 0x58 x 120 0x78
EM 25 0x19 9 57 0x39 Y 89 0x59 y 121 0x79
SUB 26 0x1a : 58 0x3a Z 90 0x5a z 122 0x7a
ESC 27 0x1b ; 59 0x3b [ 91 0x5b { 123 0x7b
FS 28 0x1c < 60 0x3c \ 92 0x5c | 124 0x7c
GS 29 0x1d = 61 0x3d ] 93 0x5d } 125 0x7d
RS 30 0x1e > 62 0x3e ^ 94 0x5e ~ 126 0x7e
US 31 0x1f ? 63 0x3f _ 95 0x5f DEL 127 0x7f
第 5回
今日の課題
色々な型の変数(char,int,float,double),if文
本日のミニプログラム
#include <stdio.h>
int main(void)
{
if(3>2)printf("OK");
if(3<2)printf("NG");
}
例題 5-1
標準入力からアルファベットの小文字を 1文字読み込み,何番目の文字かを示すプログラム
#include <stdio.h>
int main(void)
{
char komoji;
printf("アルファベットの小文字を入力してください ->");
komoji = getchar();
printf("この文字は %d番目です.\n", komoji - 96);
printf("この文字は %d番目です.\n", komoji - 'a' + 1);
}
文字型の変数は,整数型の変数と同じように加減などの演算ができます.
例題 5-2
文字型変数の扱い方と表示の例題
#include <stdio.h>
int main(void)
{
char a1,a2;
int b1,b2;
a1=65;
b1='A';
printf("文字型変数:65 ->文字%c\t65 ->数字%d\n",a1,a1);
printf("整数型変数:'A' ->文字%c\t'A' ->数字%d\n",b1,b1);
a1+=5;
b1+=5;
printf("文字型変数:65+5 ->文字%c\t65+5 ->数字%d\n",a1,a1);
printf("整数型変数:'A'+5 ->文字%c\t'A'+5->数字%d\n",b1,b1);
a2=b2=127;
printf("a2=%d\tb2=%d\n",a2,b2);
a2++;
b2++;
printf("a2=%d\tb2=%d\n",a2,b2);
}
数値「65」を%dで表示すれば,「65」となりますが,%cで表示すれば,「A」となります.
文字型変数も整数型変数も同じように使えますが,違いは扱える数の範囲です.文字型変数(8 ビット)
の下限は-128,上限は 127 になっています.文字型変数の値が 127 のときにインクリメント(+1)する
と,値は 128 ではなく,-128になります.注意しましょう.
練習問題
色々な変数のバイト数を表示します.8ビットで 1バイトになります.
sizeof()は型名,変数のサイズ(バイト数)を与える関数です.
#include <stdio.h>
int main(void)
{
char x1;
int x2;
float x3;
double x4;
printf("%d %d %d %d\n",sizeof(char),sizeof(int),
sizeof(float),sizeof(double));
printf("%d %d %d %d\n",sizeof(x1),sizeof(x2),
sizeof(x3),sizeof(x4));
}
長い文では,一つの文を複数行に分割しても構いません.
コンピュータにおける数値の扱い
整数型や実数型の変数は,それぞれすべての整数や実数を扱えるわけではなく,使用できる数値の範囲
に制限があります.使用できる数値の範囲は,処理系によって異なります.
整数として扱う型
char -128~127 (127=2^7-1)
int -2147483648~2147483647 (2147483647=2^31-1)
char は 1 バイトの大きさであり,-128~127 の範囲の数を表します.文字型と呼ばれると特別な変数の
ように感じますが,-128~127の範囲の整数を扱う整数型の変数と考えた方が良いでしょう.符号付 8バ
イトの整数とも言えます.最初の 1ビット目が,-128 を意味します.
実数(浮動小数点)として扱う型
float 単精度の実数(7桁程度)
double 倍精度の実数(14桁程度)
float として宣言する実数型は,10 進数 7 桁程度の精度の浮動小数点を扱えるようになっています.
double 型は float 型以上の精度を持つ実数型と定められており,10 進数 14 桁程度の精度の浮動小数点
を扱えるようになっています.
数値の範囲は処理系によって異なるので,新しい型を初めて使うときには,実際に数値を代入してテス
トした方が安全です.
条件判断
プログラミングでは,if文を使った条件判断は,繰り返しとともに重要なものです.
if 文では括弧の中の条件が満たされる場合,後ろの文を実行します.{}を使えば,複数の文を実行する
ことが可能です.
if(a==10)b=3; /*aが 10なら bに 3を代入する*/
if(a*10>30) {b=3;
c++;
d=0;}
/* a*10が 30より大きいとき,bに 3を代入し,cを 1増やし,dに 0を代入する*/
関係演算
a==b aと bが等しい a>b aは bより大きい
a!=b aと bが等しくない a<=b aは b以下である
a>=b aは b以上である a<b aは bより小さい
代入の a=b と関係演算の a==bは全く別なものなので注意しましょう!
関係演算の場合 b==aのように入れ替えることができますが,代入の場合入れ替えはできません.
a=>5,0<x<10のような書き方はできません.
例題
if文を使った例題
#include <stdio.h>
int main(void)
{
char moji;
printf("一文字入力してください");
moji=getchar();
if(moji=='A')
printf("入力した文字は Aです\n");
}
練習問題
標準入力から文字(アルファベット)を入力し,文字が'A'でない場合,入力した文字を表示するプログラム
を作ってみましょう.
例題
読み込んだ数値で条件の判断を行う
#include <stdio.h>
int main(void)
{
int num;
scanf("%d",&num);
printf("入力した値=%d\n",num);
if(num)printf("条件が満たされている\n");
}
-1,0,1,5などを打ち込んで実行してみましょう.実際には if文の括弧の中の数値が 0以外のときに,ifに続
く文が実行されます.
練習問題
関係演算子の処理を確認する.
#include <stdio.h>
int main(void)
{
printf("%d\n",3>2);
printf("%d\n",3<2);
}
練習問題
標準入力から整数を入力し,数値が自然数(1以上の整数)のときには「入力した値は自然数です」と表示す
るプログラムを作ってみましょう.
第 6回
今日の課題
複合条件,else,else if,ブロック
本日のミニプログラム
#include <stdio.h>
int main(void)
{
int i=-10;
if(i<0)printf("マイナス");
else if(i==0)printf("ゼロ");
else printf("プラス");
}
例題 6-1
複合条件を使って入力した文字が大文字の場合小文字に変換するプログラム
#include <stdio.h>
int main(void)
{
char moji;
printf("一文字入力してください>>");
moji=getchar();
if(moji>='A' && moji<='Z'){
printf("%c -> %c\n",moji,moji-'A'+'a');
}
else{
putchar(moji);
putchar('\n');
}
}
この例題で putchar(moji);putchar('\n');と printf("%c\n",moji);は同じ処理になります.
複合的な条件
演算 演算子 条件式 意味 例
AND && a && b aかつ bである i>0 && i<=10
OR || a || b aまたは bである i==-10 || i==10
NOT ! !a aでない !(i>10)
練習問題
次のうち真(TRUE)となるものはどれですか.
#include <stdio.h>
int main(void)
{
if(0<5 && 5<10)printf("A\n");
if(10%2==0)printf("B\n");
if(!(!(3>2)))printf("C\n");
if(!(3>2)||!(3<2))printf("D\n");
if(!(3>2)&&!(3<2))printf("E\n");
if(!((3>2)&&(3<2)))printf("F\n");
if(!(3%2==1))printf("G\n");
}
真理表
a b a&&b a||b
T(TRUE) T T T
T F(FALSE) F T
F T F T
F F F F
elseを使った if文
if(条件式)文 1;
else文 2;
条件が成立した場合(真)文 1を実行し,成立しない場合(偽)文 2を実行する.
if文で複数の命令を実行させたい場合,ブロックを使います.
if(条件式)
{文 1; 文 2; 文 3;...}
else
{文 A; 文 B; 文 C;...}
条件が成立した場合(真)文 1,文 2...を実行し,成立しない場合(偽)文 A,文 B...を実行する.
if(条件式)文 1;
if(条件式)文 1;
else 文 2;
ブロック
複数の文を{}に入れると,1 つの文と同じように扱えます.これをブロックと呼びます.ブロックでは,
見やすいところに改行を入れてください.
else if文
if(条件式 A){文 1;}
else if(条件式 B){文 2;}
else{文 3;}
練習問題 6-1
標準入力から整数を読み込み,その整数が 20以下の自然数である場合に,その値を表示するプログラム
を作りましょう.
文1
条件式
真
偽
条件式 A
真
偽
文1 文2
条件式 B
真
偽
文3
条件式
真
偽
文1 文2
例題 6-2
整数を読み込み,奇数か偶数かを判定する.
#include <stdio.h>
int main(void)
{
int num;
printf("整数を入力してください ->");
scanf("%d",&num);
if(num%2 == 0){printf("この整数は偶数です.\n");}
else{printf("この整数は奇数です.\n");}
}
この例題で if()と elseには 1文しかありませんので,{}は省略して構いません.
例題 6-3
文字を読み込み,大文字の場合小文字に変換し,小文字の場合大文字に変換する.それ以外はそのまま
表示する.
#include <stdio.h>
int main(void)
{
char moji;
printf("一文字入力してください>>");
moji=getchar();
if(moji>='A' && moji<='Z')printf("%c -> %c\n",moji,moji-'A'+'a');
else if(moji>='a' && moji<='z')printf("%c -> %c\n",moji,moji-'a'+'A');
else printf("%c\n",moji);
}
練習問題 6-2
入力された自然数を 4 で割った余りで分類し,「余りなし」「余り 1」「余り 2」「余り 3」などと表示する
プログラムを,else ifを使って作りましょう.
第 7回
今日の課題
複雑な条件分岐,#define,数学関数,場合分け(swichと case),型変換(キャスト)
本日のミニプログラム
#include <stdio.h>
#include <math.h>
#define PI 3.1415
int main(void)
{
printf("%f",sin(30.0/180*PI));
}
例題 7-1
#include <stdio.h>
#define AP 90
#define A 80
#define B 70
#define C 60
#define D 50
int main(void)
{
int a,b,c,gokei;
printf("中間試験の得点");
scanf("%d",&a);
printf("期末試験の得点");
scanf("%d",&b);
printf("出席回数");
scanf("%d",&c);
gokei=(int)(a*0.4+b*0.6);
if(c<10)printf("不合格");
else if(gokei>=AP)printf("A+\n");
else if(gokei>=A)printf("A\n");
else if(gokei>=B)printf("B\n");
else if(gokei>=C)printf("C\n");
else if(gokei>=D)printf("D\n");
else printf("不合格");
}
#define文
#define 文では AP を 90 に,A を 80 に...置き換えます.つまりコンパイルする前に,置換機能を用い
て,文字を置換したのと同じことになります.見かけ上変数 APを用意して,90を代入するのと同じよう
な働きをしますが,#define 文では変数を使いません.
#define文では見かけ上変数のように扱うことができますが,メモリを必要としません.またプログラム
中で頻繁に使う値を変更したい場合などに便利です.
型変換(キャスト)
(型)値とすると,値を違う型に変換できます.キャストとも言います.
整数から実数,または実数から整数への型変換はよく使われます.掛け算,割り算よりも型変換の処理が先
に行われます.
(例) i=(int)(100.0*sqrt(2.0)); y=(double)i/250; x=(float)1;
例題 7-2 数学関数を使う
#include <stdio.h>
#include <math.h>
int main(void)
{
float a=4.0,b=2.0;
printf("%f\t%f\n",sqrt(a),sqrt(b));
printf("%f\n",exp(1.0));
printf("%f\n",atan(1.0)*4.0);
}
数学関数を使うプログラムとそのコンパイルの方法
sqrt(a)のような平方根を求めるものは,数学関数として用意されています.これらの数学関数を利用す
るためには,int main(void)の行の前に,これらを利用することを記述しておく必要があります.例題
のように,#include <math.h>
という行を書いてください.
コンパイラによっては,オプション -lm (マイナス,小文字のエル,エム)をつける必要があります.
数学関数の引数は一般に double 型(float 型よりも扱う桁数が大きい)ですが,float 型を使っても構
いません.高い精度で計算を行いたい場合,float 型よりも double型の変数を使って下さい.
例題 7-3 直角三角形の斜辺の長さを求める
#include <stdio.h>
#include <math.h>
int main(void)
{
float a,b,c;
printf("辺 1\n");
scanf("%f",&a);
printf("辺 2\n");
scanf("%f",&b);
c=sqrt(a*a+b*b);
printf("斜辺の長さ=%f\n",c);
}
倍精度実数の読み込み
double 型の変数を scanf()で読み込むときは,scanf("%lf",&a);のようにパーセントエルエフとしてく
ださい.
例題 7-4
#include <stdio.h>
#include <math.h>
#define PI 3.14159265
int main(void)
{
float x;
x=0.0;
printf("%f,%f\n",x,cos(x/180.0*PI));
x=45.0;
printf("%f,%f\n",x,cos(x/180.0*PI));
x=90.0;
printf("%f,%f\n",x,cos(x/180.0*PI));
}
角度に関する関数の単位は度(degree)ではなく radian(180度=πrad)ですので気をつけてください.
処理系によっては#include <math.h>で,M_PIが円周率として使えます.
switch を使った場合分け
switch(値){
case 値:
case 値:
case 値:
default:
}
switch を使うと括弧の中の値に対応する case に飛んで実行を行います.対応する case が無い場合,
default:に飛びます.case と default は行き先表示のようなもので文ではないので,最後はコロン:で
す.また case に飛んだあと,switch のブロック({から}まで)から抜け出す命令が break です.berak
がないと次の case以降の処理も続いて実行します.
例題 7-5
#include <stdio.h>
#define Y1 "子\n"
#define Y2 "丑\n"
#define Y3 "寅\n"
#define Y4 "卯\n"
int main(void)
{
int i,j;
printf("生年を西暦で入力してください\n");
scanf("%d",&i);
j=i%12;
switch(j){
case 4:
printf(Y1);
break;
case 5:
printf(Y2);
break;
case 6:
printf(Y3);
break;
case 7:
printf(Y4);
break;
default:
printf("子から卯以外ですね\n");
break;
}
}
第 8回
今日の課題
whileを使った繰り返し,乱数
本日のミニプログラム
#include <stdio.h>
int main(void)
{
int i=1,a=0;
while(i<=10){
a+=i;
i++;
}
printf("%d",a);
}
例題 8-1whileを使った繰り返し
降順で 1から入力された数までの総合計を計算する
#include <stdio.h>
int main(void)
{
int i,n,total=0;
scanf("%d",&n);
i=n;
while(i>=1){
total+=i;
printf("i=%d\ttotal=%d\n",i,total);
i--;
}
printf("total==%d\n",total);
}
whileを使った繰り返し
while(条件){ブロック}
while文では括弧の中()の条件が正しいかチェックし,正しければ以下のブロック{}を実行します.条件
が正しければ,何度でも繰り返してブロック{}を実行します.以下のように書くと,iが 1から nまで処
理を繰り返します.繰り返しの処理が終わったあと,iの値は n+1になっています.
i=1;
while(i<=n){
処理
i++;
}
必要な処理が終わったあとに whileのブロックが終了するようにプログラムを組む必要があります.
練習問題 1 上の例題のプログラムで i++; の行を消してコンパイルし,実行してみましょう.何が起こ
るでしょうか.
ヒント:放置すればたぶん永遠に動き続けることでしょう.このようにプログラムが止まらない状態を,
無限ループあるいはエンドレスループ(endless loop)と言います.Ctrl-Cを入力して中断しましょう.
練習問題 21~10までの各整数の 2乗,3乗,平方根を求めて表示するプログラムを書いてみましょう.
例題 8-2 入力された数の階乗を計算する.階乗 n!=n×(n-1)×(n-2)×…×1で,0!=1です.
マイナスの数が入力されたらエラーとします.
#include <stdio.h>
int main(void)
{
int n,i=1;
float a=1.0;
scanf("%d",&n);
if(n<0){printf("ERROR \n");}
else{
while(i<=n){
a*=i;
i++;
}
printf("%d!=%f\n",n,a);
}
}
printf("%d!=%f\n",n,a);の%fを%e に書き替えて実行してみましょう.
%eは 6.204484e+23=6.204484×1023のように,実数を指数表示します.
aの型を int にしてプログラムを書き換えてみましょう.
練習問題 4 実行結果を Mathematicaや Maximaで確認しましょう.
20!(Shift+Enter)
練習問題 5 階乗を計算するプログラムを整数型の変数 aを使って書き替えましょう.
int a=1;
printf("%d!=%d\n",n,a);
例題 8-3
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i;
float x=0.0;
srand(100);
while(x<=2.0/3.0){
x=(float)rand()/RAND_MAX;
if(x<1.0/3.0)printf("グー\n");
else if(x<2.0/3.0)printf("チョキ\n");
else printf("パー\n");
}
}
乱数
rand()は整数型の乱数を生成します.#include <stdlib.h>を記述すると利用できます.乱数の生成のさ
れ方や周期はシステムによって異なります.乱数の最大値は RAND_MAX という定数に定義されています.
例題では,乱数から 0-1の範囲の実数型の乱数を作ります.
0-1/3:グー,1/3-2/3:チョキ,2/3-1:パーを表示し,パーが出たら終了します.
x=(float)rand()/RAND_MAX;の場合,乱数の値 rand()は,整数ですが,実数に変換され,そのあとに RAND_MAX
で割り算されます.x=1.0*rand()/RAND_MAX;としても同じ結果が得られます.(実数)/(整数)の結果は,実数
となります.
srand()は乱数の seed(種)を決定するもので,srand()の引数カッコの中の数を変えることで乱数の条
件を変えることができます.出てくる乱数を毎回変えるためには,時刻の情報を srand()の引数とする方
法などがあります.
おまけ(もっと学習したい人のために)
乱数の平均値を計算しています.サンプル数が多ければ,乱数の平均値は,乱数の上限のほぼ半分の値
となります.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i=1,n=100000;
float x;
while(i<=n){
x+=(float)rand();
i++;
}
printf("乱数の上限=%d\n",RAND_MAX);
printf("乱数の平均=%f\n",x/n);
}
第 9回
本日の課題
breakと continue,do while 文
本日のミニプログラム
#include <stdio.h>
int main(void)
{
int i=1,s=0;
do{
s+=i;
i++;
}while(i<=10);
printf("%d",s);
}
知っておくと便利なループの流れについて
break文
break 文は switch case 文や,while 文または for 文などで作られる繰り返し処理(ループ)から抜け
出すときに用いられます.多重の繰り返し処理の場合,break 文で最も内側の繰り返し処理から脱出しま
す.
continue文
continue文は,繰り返し処理の残りの部分を省略して繰り返し処理の先頭に戻ります.
無限ループ
繰り返し処理で条件が常に満たされる場合,無限ループとなりプログラムが終了しません.無限ループ
を止めたい場合,強制的にプログラムを終了する必要があります.
while(式){
文 A;
break;
文 B;
文 C;
}
while(式){
文 A;
continue;
文 B;
文 C;
}
while(常に真の式){
文 A;
文 B;
文 C;
}
条件式が常に真なので
無限ループとなる
do while文 do whileは文を実行した後で条件式を評価し,条件式が真である間,文を繰り返します.while
文は,ループの先頭で処理を繰り返すかどうかの判断を行いますが,do while 文はループの終末で繰り
返すかどうかの判断を行います.条件が満たされない場合は,while文は一度も処理を行いませんが,do
while文では 1度は処理を行います.while()の後ろのセミコロンを忘れないようにしましょう.
例題 9-11から 10までの合計を表示する
#include <stdio.h>
int main(void)
{
int i=1,s=0;
do{
s+=i;
i++;
}while(i<=10);
printf("%d",s);
}
練習問題例題をデクリメント i--を使って書き替えなさい.
例題 9-2 階乗を計算する
#include <stdio.h>
int main(void)
{
int i=1,s=1;
do{
s*=i;
i++;
}while(i<=10);
printf("%d",s);
式
文 do{
文 A;
文 B;
文 C;
}while(条件式);
}
練習問題 do whileを使って,2の 8乗を求めるプログラムを書きましょう.
練習問題 do whileを使って,初期値 a=10と公差 b=2 として,iが 0から 9番目までの等差数列の和を求
めるプログラムを書きましょう.
例題 9-3 整数の入力を繰り返し,0が入力されたら合計を表示し終了する
#include <stdio.h>
int main(void)
{
int i,s=0;
do{
scanf("%d",&i);
s+=i;
}while(i!=0);
printf("合計は%d\n",s);
}
例題 9-4 前の例題を breakを使って書き直したもの
#include <stdio.h>
int main(void)
{
int i=0,s=0;
do{
scanf("%d",&i);
s+=i;
if(i==0)break;
}while(1);
printf("%d\n",s);
}
練習問題 2進数 0B11111111を 10進数に変換する.1+2+4+8+・・・+128=255
#include <stdio.h>
int main(void)
{
int i=1,s=0;
do{
s+=i;
i*=2;
}while(i<=128);
printf("%d\n",s);
}
練習問題 100!の末尾に 0がいくつ並ぶか?(100!は 5で何回割ることができるか?)
#include <stdio.h>
int main(void)
{
int i=1,s=0;
do{
if(i%25==0)s+=2;
else if(i%5==0)s++;
i++;
}while(i<=100);
printf("%d",s);
}
第 10回
今日の課題
for文(for ループ)
本日のミニプログラム
#include <stdio.h>
int main(void)
{
int i;
float s=1.0;
for(i=1;i<=10;i++)s*=i;
printf("%f",s);
}
for文について
繰り返し回数があらかじめ決まっているループを実行させる場合には,for文が用いられます.for文の
一般的な構造は次のようになります.
for(初期値設定; 継続条件 ; 更新式){文;文;...}
処理を行う文が一つしかない場合にはカッコ{}を省略して
次のように書けます.
for(初期値設定; 継続条件 ; 更新式)文;
for 文の( )中の「初期値設定」と「更新式」を省略すると,
while文と同じことになり,’;’以外のすべてを省略すると無
限ループになります.
for (i= 5; i < 10; i++)
iを 5から始め,iを+1しながら 10未満まで(9まで)の間繰り
返す.
for (i= 10; i > 0; i--)
i を 10 から始め,i を-1 しながら i が 0 より大きい間繰り返
す.
for (c= 'a'; c <='z'; c++)
cを'a'から'z'まで繰り返す.
for ( x = 0.0; x <=360.0; x = x + 20.0)
xを 0.0から始め,+20.0しながら 360.0になるまで繰り返す.
for ( ; ; )
判断式がないので,無限ループとなる.
継続条件
真
偽
文(ブロック)
初期値設定
更新式
whileループと forループの対比
例題 10-11から入力された数までの合計
#include <stdio.h>
int main(void)
{
int i,sum=0,n;
printf("整数 nを入力してください");
scanf("%d",&n);
for(i=1;i<=n;i++){
sum+=i;
}
printf("1から nまでの合計=%d\n",sum);
}
練習問題 2から入力された数までの偶数の合計を求めるプログラムを作りなさい.
例題 10-2aから入力した文字までの表示を行う.
#include <stdio.h>
int main(void)
{
char a,b;
printf("英小文字を入力してください\n");
scanf("%c",&a);
printf("aから入力した文字までの表示\n");
for(b='a';b<=a;b++)printf("%c\n",b);
}
練習問題
1~10までの各整数に関して各数の 2乗,3乗,平方根を求めて表示するプログラムを for文を用いて書
いてみましょう.
int i;
i=1;
while(i<=10){
i++;
}
int i;
for(i=1;i<=10;i++){
}
例題 10-31から 100までの 3の倍数の個数を求める
#include <stdio.h>
int main(void)
{
int i,s=0;
for(i=1;i<=100;i++){
if(i%3 == 0){printf("%d\n",i); s++;}
}
printf("1から 100 までの 3の倍数の個数は%d\n",s);
}
練習問題
上のプログラムを while文を用いて書いてみましょう.
練習問題
上のプログラムをデクリメント(i--)を用いて書いてみましょう.
例題 10-4 入力された整数が素数かどうか判定する.
#include <stdio.h>
int main(void)
{
int i,n;
printf("整数 nを入力してください\n");
scanf("%d",&n);
for(i=2;i<n;i++){
if(n%i==0){
printf("素数ではありません\n");
break;
}
}
if(i==n)printf("素数です\n");
}
(注)break文を実行しないで,繰り返しを最後まで終了した場合,i==nになることに注意しましょう.
例題 10-5 二重の forループ
鶴と亀が合計で 10匹,足の数が合計で 26本の場合の鶴亀算.
#include <stdio.h>
#define N 10
#define M 26
int main(void)
{
int i,j,hiki,ashi,turu,kame;
for(i=0;i<=N;i++){
for(j=0;j<=N;j++){
hiki=i+j;
ashi=i*2+j*4;
if(hiki==N && ashi==M){turu=i;
kame=j;
}
}
}
printf("正解 鶴は%d匹 亀は%d 匹\n",turu,kame);
}
2重のループの場合,変数がどのように変化するか,表を書いて確認しましょう.また多重のループの場
合波カッコ{}の組み合わせが合っているか確認しましょう.
練習問題タコとイカが合計で 100匹,足の数が合計で 840本の場合のタコとイカの数を求めなさい.
おまけ(もっと学習したい人のために)
三重の for ループで x+y+z=20,2*x+y+z=30,x-y-z=0の解を求める
#include <stdio.h>
int main(void)
{
int x,y,z;
for(x=0;x<=100;x++){
for(y=0;y<=100;y++){
for(z=0;z<=100;z++){
if(x+y+z==20 && 2*x+y+z==30 && x+y-z==4)
printf("x=%d y=%d z=%d",x,y,z);
}
}
}
}
第 11回
今日の課題
簡単な関数,main関数とユーザー関数,プロトタイプ宣言
本日のミニプログラム
#include <stdio.h>
int wa(int x,int y)
{
return x+y;
}
int main(void)
{
printf("%d",wa(2,3));
}
例題 11-1 2つの数の差を関数を使って計算する.
#include <stdio.h>
int sa(int x,int y){
int z;
if(x>=y)z=x-y;
else z=y-x;
return z;
}
int main(void)
{
int i,j;
printf("数を入力してください\n");
scanf("%d",&i);
printf("数を入力してください\n");
scanf("%d",&j);
printf("%dと%dの差は%d\n",i,j,sa(i,j));
}
関数
C 言語のプログラムを実行したときに,必ず実行されるのが main(){}の記述です.これを main(メイン)
関数と呼びます.
複雑な処理をプログラムで記述する場合や同じ処理を繰り返す場合,まとまった処理を好きなときに呼び出せ
ると便利です.ユーザーが作った処理の手順をユーザー関数やユーザー定義関数と呼びます.
main 関数からユーザー関数を利用する場合,ユーザー関数へいくつかの値が送られます.またユーザー関数
から main関数へ処理の結果を値として送ります.main 関数からユーザー関数へ送る値を引数(ひきすう)と呼
びます.ユーザー関数から main 関数へ送る値を戻り値と呼びます.
戻り値=関数の型
関数定義の中の return(式) の式の値が関数の戻り値となります.戻り値がどのような型なのかを関数の型と
して明確に宣言しておかなければなりません.return(式)の型と関数の型は一致していなければなりません.
戻り値は 1個または無し(void)です.
引数
main 関数側で指定する引数を 実引数(じつひきすう),ユーザー関数側で指定する引数を仮引数(かりひきす
う)と呼びます.関数を呼び出すと,仮引数に実引数の値が代入されると考えればよいでしょう.従って,実
引数には,定数,変数,式(定数や変数を演算子で結合したもの) を書けますが,仮引数には,変数しか書け
ません.また,仮引数は関数を定義する際,型を宣言しておく必要があります.
対応する実引数と仮引数には同じ名前を付ける必要はありませんが,型と個数は必ず一致させなければなりま
せん.仮引数と関数内の変数の名前が重複してはいけません.引数の無い関数(void)もあります.
関数を使う場合,引数をどうするか?戻り値をどうするか?よく考えましょう.
練習問題
和を計算する関数 wa(x,y)を使ったプログラムに書き換えましょう.
例題 11-2 例題 10-1 を改良し,関数を使い 1から iまでの合計を表示するプログラムです.
main(){
j=func(a,b,c);
int func(int x, int y, int z)
{
return k;
}
a-->x
b-->y
c-->z
k-->j
関数の働き 実引数の値が仮引数
に代入され,戻り値 kの値が j に代入され
る.
関数
引数 戻り値
#include <stdio.h>
int gokei(int n){
int i,sum=0;
for(i=1;i<=n;i++){
sum+=i;
}
return sum;
}
int main(void)
{
int i;
for(i=1;i<=20;i++)
printf("1から%d までの合計=%d\n",i,gokei(i));
}
異なる関数の中で宣言される変数は,同じ名前でも,別な変数ですので注意しましょう.
(参考)例題 10-1
#include <stdio.h>
int main(void)
{
int i,sum=0,n;
printf("整数 nを入力してください");
scanf("%d",&n);
for(i=1;i<=n;i++){
sum+=i;
}
printf("1から nまでの合計=%d\n",sum);
}
例題 11-3 整数の階乗を返す関数
#include <stdio.h>
float kai(int n)
{
float x=1.0;
int i;
for(i=1;i<=n;i++)x*=i;
return x;
}
int main(void)
{
int i;
for(i=1;i<=10;i++){
printf("%dの階乗は%f\n",i,kai(i));
}
}
main()関数の中で変数 iと関数 kai()の中で使われている変数は,同じ名前でも,別なものですので注意
しましょう.
例題 11-4 プロトタイプ宣言を使った階乗を返すプログラム
#include <stdio.h>
float kai(int n);
int main(void)
{
int i;
for(i=1;i<=10;i++){
printf("%dの階乗は%f\n",i,kai(i));
}
}
float kai(int n)
{
float x=1.0;
int i;
for(i=1;i<=n;i++)x*=i;
return x;
}
関数のプロトタイプ宣言
普通は main 関数の前に,使用する関数を記述しておきます.そうしないと計算機は,main関数の中にあるユ
ーザー定義関数の引数の型と戻り値の型が,どのようなものなのか分からないので,コンパイルできません.
しかしプログラムの流れとして,main 関数を最初に書いた方が分かりやすい場合があります.このときに,
関数の名前,引数の型,戻り値の型(関数の型)を main 関数の前に宣言しておき,詳細は main 関数の後に記
述することができます.関数の名前と型を main関数の前に宣言することを,プロトタイプ宣言と言います.
実際には,ユーザー定義関数の先頭の行の")"までを main 関数の前に置いて,最後にセミコロン";"を付けれ
ば,プロトタイプ宣言になります.またプロトタイプ宣言では,関数の名前,引数の型,戻り値の型を宣言す
れば構いません.
int p(int x,int y); または int p(int,int); どちらでも構いません.
練習問題
上の例題でプロトタイプ宣言の行を削除してコンパイルしてみましょう.
練習問題
例題 11-1をプロトタイプ宣言を使ったプログラムに書き換えましょう.
一歩進んで
printf()や getchar()などの関数も,本当はプロトタイプ宣言が必要です.どこにあるのでしょうか?実はプ
ログラムを書くときのおまじないとして扱っていた,#include<stdio.h>という部分です.実際は,stdio.h
というファイルが用意されており,その中に printf()や getchar()などの関数のプロトタイプ宣言が書かれて
います.ところで main関数も関数の一つですが,main 関数は int型です.C言語の本によっては main関数の
最後に return 0;を入れて形式的に整数を返している書き方があります.
練習問題
xの絶対値を返す関数をプロトタイプ宣言を使って作ってみましょう.
練習問題
xの n乗を返す関数をプロトタイプ宣言を使って作ってみましょう.
第 12回
本日の課題
関数その 2(戻り値の無い関数,引数の無い関数,関数の内部の変数,グローバル変数)
本日のミニプログラム
#include <stdio.h>
int i;
void test(void)
{
printf("%d",i);
}
int main(void)
{
i=5;
test();
}
戻り値や引数のない関数
return文の無い(戻り値の無い)関数の場合,関数の型を voidとします.引数の無い関数は,引数の型
を void とします.
例題 12-1 戻り値の無い関数の例.値が 4 で割り切れるときに値を表示する関数を使い,100 までの 7
の倍数の中から 4 の倍数を表示する.
#include <stdio.h>
void test(int x)
{
if(x%4==0)printf("%d\n",x);
}
int main(void)
{
int i;
for(i=7;i<=100;i+=7)test(i);
関数
引数 戻り値
}
練習問題
上の例題をプロトタイプ宣言を使って書き直しましょう.
例題 12-2 引数の無い関数の例.
関数の内部で整数の値を読み込み 0以上なら平方根を返し,負なら 0を返す関数を使う.
#include <stdio.h>
#include <math.h>
float test(void)
{
int i;
float x;
scanf("%d",&i);
x=(float)i;
if(i>=0)return sqrt(x);
else return 0.0;
}
int main(void)
{
printf("%f\n",test());
}
例題 12-3 関数における値の確認.main関数とユーザー関数内の変数の変化に注意しましょう.
#include <stdio.h>
int test(int x,int y)
{
int z=0;
x*=2;
y--;
printf("x=%d y=%d z=%d \n",x,y,z);
return x;
}
int main(void)
{
int x=3,y=4,z=0;
printf("x=%d y=%d z=%d \n",x,y,z);
z=test(x,y);
printf("x=%d y=%d z=%d \n",x,y,z);
}
局所的変数(ローカル変数)
今まで使ってきた変数は,一般にその関数内だけで有効であり,これを局所的変数(ローカル変数)と呼
びます.main関数やユーザー関数内で同じ変数名が使用されていても,これらは別な物として扱われ,
お互いに影響を与えることはありません.
グローバル変数(外部変数)
これに対し,main関数やユーザー関数の外側で宣言した変数をグローバル変数(外部変数)と呼び,どの
関数からも共通して呼び出せます.ユーザー関数から returnで値を一つしか戻せませんが,ユーザー関
数で得られた複数の値を main関数でも使いたいときなど便利です.
しかし,プログラムが複雑になると,どこかで変数を書き替えたのに気がつかず,トラブルが生じるこ
とがあるので,注意が必要です.
例題 12-4
グローバル変数を使う例題
#include <stdio.h>
#include <math.h>
int i;
void func(void)
{
float x;
x=cos(i*3.14159/180.0);
printf("%d %f\n",i,x);
}
int main(void)
{
for(i=0;i<=90;i++)func();
}
#include <math.h>を使うと,M_PI として円周率が与えられています.
例題 12-5
グローバル変数 a,b,cを用いて 2次方程式の解を求める.
#include<stdio.h>
#include<math.h>
float a,b,c; /*グローバル変数*/
void kai(void)
{
float a1,a2,d;
d=b*b-4.0*a*c; /*判別式*/
a1=(-b+sqrt(d))/(2.0*a);
a2=(-b-sqrt(d))/(2.0*a);
printf("解 1=%f\n解 2=%f\n",a1,a2);
}
int main(void)
{
printf("係数 aを入力してください");
scanf("%f",&a);
printf("係数 bを入力してください");
scanf("%f",&b);
printf("係数 cを入力してください");
scanf("%f",&c);
if(b*b-4.0*a*c>=0)kai();
else printf("解はありません\n");
}
scanf()で double型の変数に値を入力する場合 scanf("%lf",&a);のように%lf(パーセントエルエフ)と
してください.
練習問題
上の例題を関数を使わないプログラムに書き替えましょう.
第 13回
今日の課題
配列の使い方その1
本日のミニプログラム
#include <stdio.h>
int main(void)
{
int a[4]={1,2,3,4};
int i;
for(i=0;i<4;i++)printf("%d\n",a[i]);
}
配列について
同じ型の変数を多数使いたい場合に,一つ一つ異なる変数名を割り当てるのは大変です.プログラムが
見にくく,エラーの原因にもなります.このような場合は,配列を用います.
例えば, int a[40]; と宣言すると,a[0],a[1],…,a[39]という 40個の変数が用意されます.変数はデ
ータを入れておく箱として考えることができます.配列の場合,図のように aという配列名と[ ]で囲
まれた配列番号 (添字) で管理されます.つまり,a[0]は 0 番目の箱,a[39]は 39 番目の箱という意味
になります.i番目の箱は a[i]と書くことで指定できます.配列の添字は必ずゼロからスタートします.
例題 13-1
#include <stdio.h>
#include <math.h>
int main(void)
{
int a[11],i;
float b[11];
for(i=0;i<=10;i++){
a[i]=10-i;
b[i]=sqrt(10.0-i);}
a[0] a[1] a[2] a[3] a[4] a[39] .....
a[i] a:配列名 i:配列番号(添字)
値
for(i=0;i<=10;i++)
printf("a[%d]=%d\tb[%d]=%f\n",i,a[i],i,b[i]);
}
配列の宣言
C言語における配列の宣言は,以下のようにして行います.
int suu[20]; /* 整数型の配列 suu[0]- suu[19]*/
float data[5][15]; /* 単精度実数型の二次元配列 data[0][0]- data[4][14]*/
char moji[20]; /* 文字型の配列 moji[0]- moji[19]*/
型としては,int,float,double,char など,これまで扱った変数と同じ型を指定できます.要素のカ
ッコ[]が 1つのものを 1次元配列,2つのものを 2次元配列と呼びます.
ここで特に注意しておきたいのは,指定する[要素の数]は添字の上限ではなく,要素の数であるという
ことです.つまり,int a[40]; と宣言された配列は,a[0]~a[39]までの 40個が用意されるのであっ
て,a[40]という配列要素は確保されていません.
配列の初期化
int suu[20]; として配列を宣言してから suu[18]++; とするとどうなるでしょうか?suu[18]が初め
から 0であるとは限りません.初めから配列に値を入れておくか(初期化),正しく配列に値を代入する
必要があります.例えば配列に全て 0を代入する場合でも,forループなどが必要です.しかし要素の数
が小さい配列の場合,配列の宣言時に,{ }の中にデータを書いておけば,自動的にデータを初期設定
することができます.int a[3]={3,2,1};
のような配列の宣言を行うと,図のようにデータが入ります.
また,配列の宣言時に初期化データが置かれているときは,[]内の値を省略して
int a[]={3,2,1};
のように書くこともできます.
C言語ではいろいろなカッコが出てきます.違いを整理しましょう.
<>(){}[]
練習問題
上の例題で赤字の部分をコメントとしてプログラムを実行してみましょう.
例題 13-2
配列を使い平均,分散,標準偏差を計算する
a[0] a[1] a[2] 3 2 1
平均 ∑−
=
=1
0
1 N
iia
Na 分散 2
1
0
2 )(1 aaN i
N
i−= ∑
−
=
σ 標準偏差 2σσ =
#include <stdio.h>
#include <math.h>
#define N 5
int main(void)
{
float a[N]={1.0,2.0,3.0,4.0,5.0};
int i;
float s=0.0,heikin,bunsan;
for(i=0;i<N;i++)s+=a[i];
heikin=s/N;
printf("平均は%f\n",heikin);
s=0.0;
for(i=0;i<N;i++)s+=(a[i]-heikin)*(a[i]-heikin);
bunsan=s/N;
printf("分散は%f\n標準偏差は%f\n",bunsan,sqrt(bunsan));
}
float a[]={1.0,2.0,3.0,4.0,5.0};としてもかまいません.
例題 13-3
配列の最大値を表示するプログラム
#include <stdio.h>
int main(void)
{
int data[8]={2,4,3,10,0,15,-3,1};
int i,max;
max=data[0];
for(i=1;i<8;i++)
if(data[i]>max)max=data[i];
printf("最大値は%d\n",max);
}
変数 maxに data[0]の値を入れておき,配列の要素が,maxを上回ったときに値を更新します.
同じ型の変数と配列の宣言は,以下のように一緒にしても,分けてもどちらでも構いません.
int i,max,data[8]={2,4,3,10,0,15,-3,1};
練習問題
配列の最小値を表示するプログラムを作りましょう.
一歩進んだ例題
素数(prime number)を計算するプログラムです.
最初は配列 s[]に全て 1を入れておきます.
次の素数を見つけ,素数の倍数は s[i]=0となります.
これを繰り返すと s[i]==1の iが素数となります.
#include <stdio.h>
#define N 100
int main(void)
{
int i,j,sp,s[N];
for(i=0;i<N;i++)s[i]=1;
for(i=2;i<N;i++){
while(s[i]==0)i++;
sp=i;
for(j=2;sp*j<N;j++)s[sp*j]=0;
}
for(i=2;i<N;i++)if(s[i]==1)printf("%d\n",i);
}
一歩進んだ例題
2次元配列を使った掃き出し法による逆行列の計算
#include <stdio.h>
int main(void)
{
int i,j,k,n=3;
float a,b,y[3][3];
float x[3][3]={{1.0,2.0,-1.0},{-1.0,-1.0,2.0},{2.0,-1.0,1.0}};
/* y[3][3]は単位行列*/
for(i=0;i<n;i++)for(j=0;j<n;j++)if(i==j){y[i][j]=1.0;}
else{y[i][j]=0.0;}
for(i=0;i<n;i++){a=x[i][i]; /* X の対角成分を 1にする*/
for(j=i;j<n;j++)x[i][j]=x[i][j]/a;
for(j=0;j<n;j++)y[i][j]=y[i][j]/a;
for(j=0;j<n;j++)if(j!=i){b=x[j][i];
for(k=i;k<n;k++)x[j][k]=x[j][k]-x[i][k]*b;
for(k=0;k<n;k++)y[j][k]=y[j][k]-y[i][k]*b;
}
}
printf("%f %f %f\n",y[0][0],y[0][1],y[0][2]);
printf("%f %f %f\n",y[1][0],y[1][1],y[1][2]);
printf("%f %f %f\n",y[2][0],y[2][1],y[2][2]);
}
掃き出し法:
逆行列を求めたい行列 Aと単位行列を横に並べ 3×6行の行列[AE]を作る.
行基本操作を行い,行列 Aを単位行列にすると,E に相当する部分が Aの逆行列になる.
行基本操作
1つの行にある数をかける.
1つの行にある数をかけたものを別の行に加える.
2つの行を入れ替える
第 14回
今日の課題
配列の続き,文字列と配列,講義のまとめ
例題 14-1
文字型配列を使った,文字列の入出力.
#include <stdio.h>
#define N 20
int main(void)
{
char a[N];
int i;
printf("文字列を入力して下さい");
scanf("%s",a);
printf("%s\n",a);
for(i=0;i<20;i++){putchar(a[i]);
putchar('\n');}
}
scanf()で文字列を入力すると文字が一つずつ配列に代入され最後に'\0'が入ります.'\0'は文字列の終
了を意味する文字(ヌル文字)です.
文字列を扱った配列の初期化は次のように行います.
char a[N]={'1','2','3','4','\0'};
文字と文字列の違い
文字は文字型変数に代入することができ,整数と同じように加減算などができます.
文字は'z'や'\n'のようにシングルコーテーション「'」で囲みます.
文字列は"abc"のようにダブルコーテーション「"」で囲みます.実際には,文字列"abc"の場合,'a'+
'b'+'c'+'\0'のように最後に,文字列の終端を意味するヌル文字'\0'が付きます.
一文字の文字列"a"と文字定数'a'は異なることに注意しましょう.
配列に文字列を代入する
単語のように文字数が決まっていない文字列を配列に格納する場合,文字列の終端を意味するヌル文字
'\0'を使います.十分な大きさの配列を用意しておけば,文字数に関わらず必要な文字列の入出力がで
きます.ヌル文字より後ろの配列の値は無視されます.
例えば要素の数が 5の配列 a[]に文字列"abc"を代入すると,各要素は次のようになります.
a[0]='a'
a[1]='b'
a[2]='c'
a[3]='\0'
a[4]=?
5番目の要素 a[4]には,何が入っているか未定です.
配列 a[]に代入した文字列の表示は,次のように行います.
printf("%s\n",a);
このときヌル文字の前までの文字が表示されます.
例題 14-2
文字数の計算
#include <stdio.h>
#define N 20
int main(void)
{
char a[N];
int i;
printf("文字列を入力して下さい");
scanf("%s",a);
printf("%s\n",a);
for(i=0;i<N;i++){
if(a[i]=='\0')break;
putchar(a[i]);
}
putchar('\n');
printf("文字数は%dです",i);
}
'\0'が入っている配列の番号が文字数に対応しています.
ポインタ(一歩進んだ説明)
変数や配列はコンピュータのメモリ上の決められた場所(アドレス)が指定され,ここにデータが保存
されます.ポインタは変数や配列などのデータのアドレスの値です.
&変数名で変数のポインタ(変数のアドレス)となります.配列の場合,配列のカッコをはずすと配列の
最初の値[0]のポインタ(変数のアドレス)となります.
*ポインタでポインタの示すアドレスの値となります.
scanf()では,ポインタで値の保存先を指定します.このため&変数名となっていました.scanf()で配列
に文字列を入力する場合は,&は不要です.
ポインタを使うと,使用するメモリの数を減らしたり,ユーザ関数からメイン関数の変数に直接アクセ
スしたりすることができます.
#include <stdio.h>
int main(void)
{
int a[3]={4,5,6},i,x=5,y=10,z,*p,*q;
p=a; //配列の先頭のアドレスを pに代入
for(i=0;i<3;i++)printf("%d\n",*(p+i));
printf("x,y=%d %d\n",x,y);
p=&x; //変数 xのポインタを pに代入
q=&y; //変数 yのポインタを qに代入
printf("p,q=%d %d\n",p,q);//ポインタの値を表示
printf("*p,*q=%d %d\n",*p,*q);//ポインタの示すアドレスの値を表示
//ポインタを使い変数 x,yの値の交換
z=*p;
*p=*q;
*q=z;
printf("x,y=%d %d\n",x,y);
}
まとめ
特に以下の点をしっかりと復習してください.
基本的なプログラムの流れを理解できるか?処理の結果を予想する.
if文や for ループでプログラムの流れを制御できる.
&&(AND)や||(OR)を用いた複合条件が理解できる.
色々な変数の型:int,float,double,char
演算式,自己代入型演算子,
printf(),scanf(),getchar(),putchar()の使い方
書式指定子(%d,%f,%c,%s)と\n,\tなどの使い方.
演算の処理の順番(優先順位)がある.上から優先順位が高い.(int)(7/2+7%4+7.0/4) ?
*,/,%
+,-
<,<=,>,>=
==,!=
整数同士の割り算では小数点以下は切り捨てられる.
整数と実数が混じった演算の結果は,実数になる.
値の左に(型)を付ければ,異なる型に変換される.
式の結果を変数に代入する場合,変数の型に結果が変換される.
#defineの使い方,関数の使い方,配列の使い方
=と==の違い
例題 14-3wile,do while,forの比較 1から 10までの和
(wile)
#include <stdio.h>
int main(void)
{
int i=1,s=0;
while(i<=10){
s+=i;
i++;
}
printf("%d",s);
}
(do while)
#include <stdio.h>
int main(void)
{
int i=1,s=0;
do{s+=i;
i++;
}while(i<=10);
printf("%d",s);
}
(for)
#include <stdio.h>
int main(void)
{
int i,s=0;
for(i=1;i<=10;i++){
s+=i;
}
printf("%d",s);
}
例題
C言語の復習を兼ねた例題
#include <stdio.h>
#include <math.h>
#define PI 3.14159
int main(void)
{
int i=45,j=0;
float x;
printf("sin(%d)=%f\n",i,sin((float)i*PI/180.0));
for(i=1;i<10;i++)if((i%3==0) || (i<5))j+=i;
printf("%d\n",j);
i=(int)(4/5+4.0/5);
x=4/5+4.0/5;
printf("%d %f\n",i,x);
printf("アルファベットの小文字を入力してください\n");
scanf("%c",&i);
if(i>='a' && i<='z')printf("%cは%d番目の文字です\n", i,i-'a'+1);
else printf("アルファベットの小文字ではありません\n");
}
これからの勉強
講義は本日で終了します.あとはポインタや構造体などを学習すれば,C言語のほとんどの範囲をカバー
したことになります.
今回の講義で C 言語のプログラミングの基礎は理解できたはずです.プログラミングはやらないとすぐ
に忘れてしまいます.
理解が足りなかった分は,夏休みを利用して,しっかりと復習をして下さい.
付録
//&変数はポインタ(データのアドレス)となる
#include <stdio.h>
int main(void)
{
int i,address;
// scanf("%d",&i);
address=(int)(&i);
printf("%d\n",address);
scanf("%d",address);
printf("%d\n",i*2);
}
//配列の[]を除くとポインタ(配列の先頭のアドレス)となる.
//*(ポインタ)とするとポインタに相当するアドレスに格納されている値となる
//int型は 4バイトなので,ポインタの値が 1ずつではなく 4ずつ増えることに注意.
#include <stdio.h>
int main(void)
{
int data[]={3,4,5,6,7};
int i;
for(i=0;i<5;i++){
printf("%d\n",data+i);
printf("%d\n",*(data+i));
}
}
Unix上のエディタ viの使い方
起動 vi [ファイル名 ...]
指定されたファイルが無い場合は新規作成モードとなる.ファイル名にはワイルドカード('*', '?'など)も使用可能.
編集モード タイプした文字がそのまま反映される.Escでコマンドモードへ戻る.
コマンドモード 以下に示す各種コマンドが使える.起動直後はこのモード.(iで編集モードへ)
コマンドモードにおける各種コマンド (各コマンドの前に数字を打つと,その回数分だけ同じ動作を繰り返す)
:q セーブせずに終了
:q! 変更した行もセーブせずに終了
:w セーブするが終了しない.
:wq セーブして終了
編集モードへ移るためのキー
i 現在のカーソル位置から挿入.
R 現在のカーソル位置から置換.
A 現在行の末尾に追加.
O 現在行の前に行挿入.
o 現在行の次に行挿入.
カーソル移動キー h(←) 左 j(↓) 上 k(↑) 下 l(→) 右
0 行頭へ
$ 行末へ
[Enter] 次の行の先頭へ
w 次の単語へ
b 前の単語へ
ctrl + f 次画面へ
ctrl + b 前画面へ
1G 文頭へ
G 文末へ
nnG nn行目へ
変更キー
x 1文字削除
dd 1行削除(カット)
cw(Change Word) 1語変更
c$ カーソル位置から行末まで変更
dw(Delete Word) 1語削除
d$ カーソル位置から行末まで削除
検索 /正規表現 前方検索
?正規表現 後方検索
n 次の候補
N 前の候補
カット/コピー&ペースト
yy 1行コピー
dd 1行カット
p ペースト(張り付け)
その他 .(ドット) 直前の変更操作の繰り返し
u 直前の変更操作の取り消し(何回でも戻れる)
gccのオプション
-Wunused 未使用の変数をチェック
-Wreturn-type 関数の返却値と型の整合性
[例]main関数の終了が exit関数,或いは return文でないと次の warning が出る.
control reaches end of non-void function
-Wformat printf や scanf の変換指定子のチェック
-Wimplict 関数や引数の暗黙的宣言のチェック
-Wuninitialiezed 変数の初期化チェック(但し,最適化用オプション利用時)
-Wall 上記オプションを含む warning用オプションのすべて.
どのオプションが含まれるかはコンパイラのマニュアルを.
-O 処理の最適化.最適化については,他のオプション -O2 などあり.
どのような最適化が行われるかはコンパイラのマニュアルを.
-o 実行ファイル名を指定.
-c オブジェクトファイルの生成.
-S 翻訳処理のみ.アセンブリ言語ファイルが生成される.
Cygwinのインストール
Cygwinのサイトにアクセスする. http://www.cygwin.com/
Install or update now!をクリックする.
ファイルのダウンロード>実行を選択する.
次へをクリックして Install from Internetを選択する.
Choose A Download Siteで日本のサイト Ftp://XXXXXXX.jpを選ぶとダウンロードが早い.
このままインストールすると gcc(Cコンパイラ)がインストールされないので,
SelectPackagesの画面で DevelDefaultをクリックする
Packagesのリストの中に gcc-core:C compilerというのがあるのでチェックを入れる.
あとは次へを続けてクリックしていけば Cygwinがインストールされて gccが使えるはずです.