今日やること 基礎演習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
© Copyright 2024 Paperzz