基礎演習3 C言語の基礎(2) 今日やること 先週の復習 先週の内容

今日やること

基礎演習3 C言語の基礎(2)



第01回(2010年06月16日)


先週の復習
種々のファイル
リファレンスの読み方
基本的な出力
変数と配列
型変換とキャスト
先週の内容
はじめに
 計算機とは
 計算機言語を学ぶにあたって
 C言語について
 アルゴリズムとデータ構造
 アルゴリズム
 データ構造

先週の復習
3/59
計算機とは

ビットとバイト
計算機は、ざっくりと言って、CPUとメモリ、
入出力装置からなる。


計算機
入出力
装置
CPU
メモリ
外部と
データを
やりとりする
データを
処理する
データを
保存する

日常、人は、値(数)は10進数で、文字は文字として使
用している。
一方、計算機の内部では、すべてのデータは 0,1 で管
理されている。0,1 しか取り扱うことができない!
また、計算機は、メモリにデータを蓄えている。
単位は、
 bit
1bit
0 もしくは 1 のどちらかを保存。
 byte
1bitが8つ集まっている。
1byte
例え話(2)
上級言語


人間は、2進数を会話するようにできていない!
人間が計算機に指示しやすく、つまり、プログラミング
しやすくしたものが、上級言語。
こういう処理
をやりたい
なぁ
計算機
0000
0001
0002
0003
0004
了解。
理解した。
処理
 プログラミングと対応させると......
 個々のブロックの形を把握する。
→ 個々の命令を理解する。
 組み上がったブロック例を学ぶ
→ 他のサンプルプログラムを理解する。
人
10001001
01101010
10111010
11011011
変換
 自分で組んでみる
→ 自分でプログラムを組んでみる。
printf()
get()
put()
while()
データ処理とデータ構造


入力

格納
データ
データ
…

データ構造:
コンピュータにどのように組織化して格
納するか。
データ処理:
データを加工する方法や、その順番。
プログラム:
データを加工しつつ、正しい出力を求め
ていくプロセスの記述。
プログラムを書くときには...
加工
プログラムを行うときに考えること...
 データ構造:
目的を達成するためには、どのようなデータが必要
になるか。どのように保存したら良いか。
変数等の宣言に関係
加工

データ
目的を達成するためには、何を行えばよいか。どの
ような順番で行えばよいか。
処理の内容や順番等に関係

プログラム→データ処理+データ構造
出力
9/59
結局の所、色々練習して、経験値を積むのが良いです10/59
C言語のソースファイル

C言語のソースファイルはテキストファイルで書
かれている。
 コンパイラを用いて、実行可能な形にする。
 最小なソースコード
main(){
}
もちろん、このプログラムは、何もしません。
コンパイルとは

テキストで書かれているソースファイルを、計算
機が理解できる形のファイルに変換すること。
ここの処理
こういう処理
をやりたい
なぁ
計算機
0000
0001
0002
0003
0004
了解。
理解した。
処理
人
10001001
01101010
10111010
11011011
変換
printf()
get()
put()
while()
C言語におけるコンパイル

この授業では、コンパイルは、gccを用います。
C言語における
ファイル構成
gcc sample.c

cygwinの場合 a.exe というファイルができます。
./a
として実行します。
14/59
C言語と関数 (1)
典型的なソースファイルの構成
#include<stdio.h>
#include<stdio.h>
#include<pow.h>
#include<pow.h>
ヘッダファイルをinclude。
main(){
main(){
文
文
x=pow(10);
x=pow(10);
y=sqrt(10);
y=sqrt(10);
}}

入力
mainは必ずある


中に、関数が沢山並んでいる

C言語と関数 (2)

入力は
引数として与える
関数
pow(
pow( xx ))
関数
出力
個々の関数について、「何を何個入力として与えるか」
「何を出力するか」は、決められています。
C言語は、基本的に関数からなりたちます。
関数は、自作することもできます。
ヘッダファイルとライブラリ(1)
「関数」を利用する場合は、「関数名」と「丸括弧で囲ま
れた部分に記述する引数」により、記述します。
入力
C言語の「関数」とは、入力を与えると出力を返すよう
な"もの"です。



出力
出力は
関数が
置換されると
思えばOK

関数を1からすべて書くのは面倒くさい!
C言語には、便利な関数が、沢山準備されている。
どの関数を使うのか? その関数の入出力は?:
それを記述しているのがヘッダファイル。
使用する関数が含まれているヘッダファイルを
#includeする必要がある。
それらの関数の具体的な動作は?:
それが書かれているのがライブラリ。
すでに計算機が理解できる2進数表記になっている。
ヘッダファイル



#include<stdio.h> って何をしてるの?
 /usr/include/stdio.h を取り込んでいる。
 stdio.h には、標準的な入出力関係する命令や定義が
含まれている。
入出力を伴う場合は、#include する。
逆に、伴わない場合は include する必要はない。
他にも、math.h には、標準的な数値演算の命令や定義
が入っている。
 使用するときは、#include<math.h> とする。
include は、他のファイルを取り込むときに使用。
演習:ヘッダファイル

ls /usr/include/




として見てみよう。
ライブラリとのリンク(1)
ヘッダファイルは、関数に関しては「関数の名前と入出
力」しか書かれていない。
実際に行う内容が記述されているのが、ライブラリ。
すでにコンパイル済みで、計算機が理解できる状態に
なっている。


使用するライブラリを指定するには、ライブラリファイル
をコンパイルするときに指定する。
コンパイルするときにライブラリを指定すると、「リンク」
と呼ばれる作業が行われる。
UNIXの場合、数値演算の命令を使用する場合は、
libm.so か libm.aとリンクする必要がある。

libm.so とリンクするように指定
動的リンクしたライブラリの場合、ldd で確認できる。
ldd ./a.out
Cynwinも(UNIXとは構成が違うが)ライブラリを多く持っ
ている。.dll というファイルなので、ファイルがあることを
ls /usr/bin/*.dll
gcc -lm sample.c

複数の機械語のプログラムを連結する作業を、「リン
ク」という。
リンクの仕方は2種類有る。
 静的リンク:
コンパイル時にライブラリを含めた1つのファイルに
してしまう
 動的リンク:
実行時にライブラリを取り込む方法の、2種類がある。
演習:ライブラリ
ライブラリとのリンク(2)

として、ヘッダファイルが沢山あることを見てみよう。
ヘッダファイルの中身を
less /usr/include/math.h
ライブラリ

Cynwinは、ヘッダファイルを
/usr/include/
以下に持っている。

として確認してみよう。
実際に、どのライブラリと動的リンクしているか、前回作
成したa.exeにたいして
ldd ./a.out
として確認してみよう。
ヘッダファイルとライブラリ(2)
ヘッダファイルとライブラリは、無数にあります。
プログラミングをする際は、
 どの関数を利用するのか 。
つまり、どのヘッダファイルを#include して、どのラ
イブラリとリンクするのか。
を把握しておく必要があります。


リファレンスの読み方
26/59
リファレンス
リファレンスの書かれ方

C言語のリファレンスとは、要するに、関数のリ
ファレンス
 引数として何を与えるか
 引数と返値の型
 関数が実行する内容
 関数のリファレンスには、何通りか流儀がある。
 自分で関数を作るときや、/usr/include/ 以下を
覗いた時など用に、読めた方がよい。
以下の3つは、同じ事を言っている。
その1: double
doublesample(double,
sample(double,int)
int)
この後、引数と戻り値の関係や、関数の動作が書かれます。
その2: double
doublesample(double
sample(doublex,
x,int
inty)
y)
この後、引数と戻り値の関係や、関数の動作が書かれます。
その3: double
doublesample(x,
sample(x,y);
y);
double
doublex;
x;
int
inty;
y;
この後、引数と戻り値の関係や、関数の動作が書かれます。
27/59
リファレンスの例
28/59
リファレンスの例
名前 pow – 累乗関数
名前 pow – 累乗関数
書式 #include
#include <math.h>
<math.h>
書式 #include
#include <math.h>
<math.h>
double
double pow(double
pow(double x,
x, double
double y);
y);
関数の名前
関数の概要
 ヘッダ
 引数の数
 引数の型
 戻り値の型
等。
double
double pow(double
pow(double x,
x, double
double y);
y);
ライブラリ math library (libm, -lm)
ライブラリ math library (libm, -lm)
説明 x の y 乗の値を返す。
説明 x の y 乗の値を返す。
ライブラリの名前、
ファイル名、
リンクするときの引数
関数の説明、挙動
コマンドプロンプトで、man pow と打つと、
見ることができます(たぶん英語です)
29/59
コマンドプロンプトで、man pow と打つと、
見ることができます(たぶん英語です)
30/59
演習:リファレンス

Cygwinは、リファレンスを持っている。
man pow
基本的な出力(1)
printf() その1
として、powのリファレンスを見てみよう。
man は C言語の命令ではなく、cygwinの命令です。
C言語の関数だけではなく、ls や mkdir 等のマニュアル
も参照することができます。

man ls
man mkdir
として、見てみましょう。
32/59
printf の format
printf(format [,arg] ...);


format に従って標準出力に出力を行う関数。
format の部分は、文字列である。
型と変数と配列
 %から始まるものは、順番にargを参照して変換される。
 それ以外(たんなる文字とか)は、そのまま。

例: int i;
char c;
空白や改行も、そのままでる
char str*;
printf("print %d %c %s¥n",i,c,str);
そのまま出る
符合無し10進数に置換される
文字列に
置換される
文字に置換される
33/59
C言語と型



34/59
変数
 値を保存しておく「入れ物」を使用することができる。
C言語では、この「入れ物」のことを「変数」と呼ぶ。
 使用する場合は、「こういう名前の変数を、こういう値を
保存するのに使う」と宣言しておく必要がある。
C言語では、すべての値に「型」が決められている。
4 と 4.0 は
 数学的な意味は同じ
 文字として表現したときは違う場合もある
(例:物理の有効桁数とか)
 C言語では、内部での2進数表現が異なる。
C言語では、さまざまな「型」があります。
 整数型(例:4, 10 とかの整数値)
 倍精度実数(例:3.1415 とかの実数値)
 文字型(例:a,b,c とかの1文字)
宣言方法
データ型 変数名 [, 変数名...];
#include<stdio.h>
35/59
main(){
int i;
i=1;
printf("%d¥n",i);
}
C言語と型(2)


よく使われる「データ型」は、次のようなものがある。
: 符合付き整数(-5246, 1234)

: 符合無し整数(1234, 435)

: 符合付き整数(intより大きい値を扱える)

: 符合無し整数( intより大きい値を扱える)

: 単精度浮動小数点型(3.1415)

: 倍精度浮動小数点型
: (floatより大きい値を扱える)
 char
: 文字
 void
: 型なし
データ型は、「その箱に何があるかの意味」とともに、「内部でど
のように2進数でデータを保存するか」を規定しています。


代入
int
unsigned int
long
unsigned long
float
double
37/59

i=10
i=10
;;
加算代入:「+=」という記号を用いて行う。
例:変数 i の値に2を加えて i に代入したい

i+=2
i+=2
;;
他にも、減算代入(-=)、乗算代入(*=)、除算代
入(/=)等、一通りあります。
38/59
再掲:
printf の format
参照

変数には、データを保存しておくことができます。
変数にデータを保存する作業を「代入」といいます。
 代入:「=」 を変数の右側に書いて行う。
例:変数 i に10を代入したい
変数が保存しているデータを見ることができる。
変数が保存しているデータを見る作業を「参照」と
いいます。
 参照:変数名を書いて行う。
例:変数 i に変数 x が保存しているデータを
代入したい場合
printf(format [,arg] ...);


format に従って標準出力に出力を行う関数。
format の部分は、文字列である。
 %から始まるものは、順番にargを参照して変換される。
 それ以外(たんなる文字とか)は、そのまま。

i=x;
i=x;
例: int i;
char c;
空白や改行も、そのままでる
char str*;
printf("print %d %c %s¥n",i,c,str);
記号「=」の右側と左側で、変数の役割が違って
いることに注意する。
そのまま出る
符合無し10進数に置換される
39/59
演習:変数とprintf (1)
#include<stdio.h>
#include<stdio.h>
実行してみましょう
int
int main(){
main(){
int
int x,y;
x,y;
char
char c;
c;
}}
x=10;
x=10;
y=x;
y=x;
c='a';
c='a';
x+=5;
x+=5;
printf("print
printf("print %d
%d %d
%d %c
%c %d¥n",x,y,c,
%d¥n",x,y,c, 400);
400);
文字列に
置換される
文字に置換される
40/59
演習:変数とprintf (2)
#include<stdio.h>
#include<stdio.h>
int
int main(){
main(){
int
int x,y;
x,y;
char
char c;
c;
}}
それぞれの行が実行されたとき、
変数の値がどうなるか、記入しましょう。
x
y
c
?
?
?
x=10;
x=10;
y=x;
y=x;
c='a';
c='a';
x+=5;
x+=5;
printf("print
printf("print %d
%d %d
%d %c
%c %d¥n",x,y,c,
%d¥n",x,y,c, 400);
400);
配列 その1
配列 その2
 配列とは、変数が沢山並んだようなもの。
 配列に値を代入・参照したい場合は、
 使用する場合は、宣言しておく必要がある。
配列名[番号]
のようにします。
データ型 配列名[個数];
#include<stdio.h>
main(){
int t[10];
...
}
#include<stdio.h>
tという名前の
サイズ10の
整数型の
配列を宣言
main(){
int t[10];
t[2]=2;
t[5]=t[2];
}
t[0] t[1] t[2] t[3] t[4] t[5] t[6] t[7] t[8] t[9]
t[0] t[1] t[2] t[3] t[4] t[5] t[6] t[7] t[8] t[9]
1
1
演習:配列
配列 その2
 配列を使うときの注意。
 t[10] のように宣言すると、
t[0]~t[9] までの10個が使用できるようになる。
t[1]~t[10]までではないので注意。
 宣言してない部分まで使用しない。
例えば、上の例で、 t[10]=1 とかしてはいけない。
大抵のCコンパイラは、何も警告してくれません。
 データ型 配列名[番号] [番号] のようにすると、2次元配
列が利用できます。
#include<stdio.h>
#include<stdio.h>
main(){
main(){
int
int x[10];
x[10];
int
int y[5][5];
y[5][5];
実行してみましょう
x[2]=2;
x[2]=2;
x[5]=x[2];
x[5]=x[2];
y[1][2]=x[2];
y[1][2]=x[2];
}}
printf("%d
printf("%d %d
%d %d¥n",x[2],
%d¥n",x[2], x[5],
x[5], y[1][2]);
y[1][2]);
算術演算 その1
 C言語では、様々な演算子が使用できる。
算術演算
47/59
算術演算子:
論理演算子:
x + y : x と y の和
A && B :AかつB
x - y : x と y の差
A || B :AもしくはB
x * y : x と y の積
x / y : x を y で割った商
x % y : x を y で割った余り
関係演算子:
x < y : x < y のとき真(1)、さもなければ偽(0)
x <= y : x <= y のとき真(1)、さもなければ偽(0)
x > y : x < y のとき真(1)、さもなければ偽(0)
x >= y : x > y のとき真(1)、さもなければ偽(0)
x == y : x = y のとき真(1)、さもなければ偽(0)
x != y : x != y のとき真(1)、さもなければ偽(0)
演習:算術演算 (1)
算術演算 その2
 インクリメントとディクリメント
インクリメント → 増加
ディクリメント → 減少
A)
B)
C)
D)
#include<stdio.h>
#include<stdio.h>
x++ : xの値を評価後、インクリメント
++x : xの値をインクリメント後、評価
x-- : xの値を評価後、ディクリメント
--x : xの値をディクリメント後、評価
例:
A)
B)
C)
D)
実行してみましょう
main(){
main(){
int
int x,y;
x,y;
y=x++ : y=x; x=x+1; : 値を渡してから、xに1を加える
y=++x : x=x+1; y=x; : xに1を加えてから、値を渡す
y=x-- : y=x; x=x-1; : 値を渡してから、xから1を引く
y=--x : x=x-1; y=x; : xから1を引いてから、値を渡す
}}
x=2+3;
x=2+3;
printf("001
printf("001 ->
-> %d¥n",x);
%d¥n",x);
y=x++;
y=x++;
printf("002
printf("002 ->
-> %d
%d %d
%d ¥n",x,y);
¥n",x,y);
y=++x;
y=++x;
printf("003
printf("003 ->
-> %d
%d %d
%d ¥n",x,y);
¥n",x,y);
演習:算術演算 (2)
#include<stdio.h>
#include<stdio.h> それぞれの行が実行されたとき、
main(){
main(){
int
int x,y;
x,y;
}}
変数の値がどうなるか、記入しましょう。
実行してみましょう
x
y
?
?
型変換とキャスト
x=2+3;
x=2+3;
printf("001
printf("001 ->
-> %d¥n",x);
%d¥n",x);
y=x++;
y=x++;
printf("002
printf("002 ->
-> %d
%d %d
%d ¥n",x,y);
¥n",x,y);
y=++x;
y=++x;
printf("003
printf("003 ->
-> %d
%d %d
%d ¥n",x,y);
¥n",x,y);
52/59
型変換(1)
型変換(2)
次のようなプログラムの場合……。
#include<stdio.h>
#include<stdio.h>
int
int i;
i;
double
double d;
d;
main(){
main(){
i=2;
i=2;
d=i;
d=i;
printf("%f¥n",d);
printf("%f¥n",d);
}}

double型の変数に
整数型の変数iの値を
代入している!
C言語では、自動的に型変換が行われる。
 型の違う変数へ代入。
double の変数に int を代入等。

関数の引数として、異なる型の値を代入。
pow(x,y)のxとして整数値を渡す等。

大丈夫。
C言語では、自動的に型変換を行い、
代入してくれます。
今回も、double型の変数dには
2という値が代入されます。
53/59
できる限り、情報を失うことがないように変換する。
 int から double や、float から double は、情報を
失うことなく、きちんと変換する。
 double から int や double から float は、変換する
際に情報が欠落する。
54/59
強制的な型変換(キャスト)

計算結果の型
強制的に型変換を行うこともできる。
 (型名)を、変数や値につける。
#include<stdio.h>
#include<stdio.h>
int
int i;
i;
double
double d;
d;
main(){
main(){
i=2;
i=2;
d=(double)i;
d=(double)i;
printf("%f¥n",d);
printf("%f¥n",d);
}}
計算式中に複数の型が現れるときは、
優先順位に従って計算結果の型が決まる
int 型の変数 i の値を
double 型に変換したのち、
d に代入。
優先順位
int → (unsigned int →) long → (unsigned long →)
d=i としたときと同じ。
float → double → long double
気にしなくてもプログラムを書
くことができる場合も多い。
しかし、型変換を意識しない
といけない場合もある。
55/59
演習:型変換
実行し、何故そのような結果に
#include
#include <stdio.h>
<stdio.h>
なるか、考えましょう
main(){
main(){
printf("001->
printf("001-> %f¥n",5.0/4.0);
%f¥n",5.0/4.0);
printf("001->
printf("001-> %f¥n",5/4);
%f¥n",5/4);
printf("002->
printf("002-> %f¥n",5/4.0);
%f¥n",5/4.0);
printf("003->
printf("003-> %f¥n",(double)5/4);
%f¥n",(double)5/4);
printf("004->
printf("004-> %f¥n",(double)(5/4));
%f¥n",(double)(5/4));
}}
例:
 int型 + long型 = long型
 int型 + double型 = double型
解説:型変換
次の printf がどのような値を出力するか答えなさい。
 printf("%f¥n",5.0/4.0);
1.250000
 printf("%f¥n",5/4);
何らかの値がでます。
 printf("%f¥n",5/4.0);
1.250000
 printf("%f¥n",(double)5/4);
1.250000
 printf("%f¥n",(double)(5/4));
1.000000
解説 その1
 printf("%f¥n", 5.0/4.0);
1.250000
 5.0はdouble型、4.0は整数型
double型/double型の計算結果はdouble型
 計算結果は1.250000 となり、それが出力される。
優先順位
int → (unsigned int →) long → (unsigned long →)
float → double → long double
解説 その2
 printf("%f¥n",5/4);
何らかの値がでます。
計算結果も整数型に
 5は整数型、4も整数型
 printfは自動的に型変換を行ってくれません。
 整数型があるメモリの部分を浮動小数点と
して解釈して、何かしら出力する。
優先順位
int → (unsigned int →) long → (unsigned long →)
float → double → long double
解説 その3
 printf("%f¥n",5/4.0);
1.250000
 5は整数型、4.0はdouble型
整数型/double型の計算結果はdouble型
 計算結果は1.250000 となり、それが出力される。
優先順位
int → (unsigned int →) long → (unsigned long →)
float → double → long double
解説 その4
 printf("%f¥n",(double)5/4);
1.250000
 (double)5はdouble型、4は整数型
double型/整数型の計算結果はdouble型
 計算結果は1.250000 となり、それが出力される。
優先順位
int → (unsigned int →) long → (unsigned long →)
float → double → long double
解説 その5
 printf("%f¥n",(double)(5/4));
1.000000
 計算の順番に注意!
 (5/4)が行われた後、(double)でキャストされる。
 (5/4)の計算結果は整数型の値 1 に
 整数型の値 1 を(double)でキャストした結果、
1.000000になる。
おわりに
優先順位
int → (unsigned int →) long → (unsigned long →)
float → double → long double
来週以降にやること







構造化プログラミング
繰り返し(whileとfor)、分岐(ifとswitch)
変数とアドレス
ポインタ
関数と値渡し、アドレス渡し
スコープ
構造体
64/59