前回の復習
4.プログラミング応用 制御と繰り返しと色々
基本的な使い方はJavaScriptと同じ 制御文 プログラムの流れを変える制御構造 if文 switch文 基本的な使い方はJavaScriptと同じ
if文 「条件式の値が真(1)ならば、{ 〜 }の中の文を処理する」というもの。逆に、偽(0)ならば処理ない。 if( 条件式 ){ 文(いくつでも) } 「条件式の値が真(1)ならば、{ 〜 }の中の文を処理する」というもの。逆に、偽(0)ならば処理ない。
else ifやelseを使うと以下のようなことができます。 int a = 18; if(a >= 20){ printf("%dは20以上です\n", a); }else if(a >= 15){ printf("%dは15以上です\n", a); }else if(a >= 10){ printf("%dは10以上です\n", a); }else if(a >= 5){ printf("%dは5以上です\n", a); }else{ printf("%dは5より小さいです\n", a); }
プログラムの書き方 プログラムは書き方が必ずしも1つとは限らない。 if文は英語の意味の通り「もし~だったら…する」とい う条件分岐を作る制御文である。 条件が「成り立った場合」と「成り立たなかった場合」 の2通りのプログラムの流れを用意することができ るのである。 プログラムの流れを必要に応じて変えていくことに よって、自分の思うままにプログラムを動かすことが 可能になる。
switch文 int num = 2; switch(num){ case 1: printf("1です\n"); break; case 2: printf("2です\n"); case 3: printf("3です\n"); default: printf("1~3までの数字だけです!\n"); }
switch~case~break~default switch文は複数のcaseという選択肢の中から式の値に合うもの(真)を選び、その処理を実行します。式の値がcaseのどれにも当てはまらない(偽)ときはdefaultに進みます。 各選択肢の最後にはbreak文を記述し、選択した処理のみを行うようにします。
実行してみよう int month = 7; if((month == 12) || (month == 1) || (month == 2)){ printf("冬\n"); }else if((month >= 3) && (month <= 5)){ printf("春\n"); }else if((month >= 6) && (month <= 8)){ printf("夏\n"); }else if((month >= 9) && (month <= 11)){ printf("秋\n"); }else{ printf("1から12の値を入力してください\n"); }
制御文はC言語もJavaScriptも同じ 普通に使っていきましょう!
基本的な使い方はJavaScriptと同じ 繰り返し(反復処理) プログラムの処理を繰り返す制御構造 for文 while文 do~while文 基本的な使い方はJavaScriptと同じ
実行してみよう int wa=0; int seki=1; for(int i=1; i <= 10; i++){ wa += i; seki *= i; } printf("和は%d 積は%d \n", wa, seki);
for文 for(初期化式; 条件式; 制御変数の更新){ 処理 }
実行結果は同じ、forがwhileになっただけ 実行してみよう int wa=0; int seki=1; int i=1; while(i <= 10){ wa += i; seki *= i; i++; } printf("和は%d 積は%d \n", wa, seki); 実行結果は同じ、forがwhileになっただけ
while文 while(条件式){ 処理 }
実行結果は同じ、forがdo~whileになっただけ 実行してみよう int wa=0; int seki=1; int i=1; do{ wa += i; seki *= i; i++; } while(i <= 10); printf("和は%d 積は%d \n", wa, seki); セミコロンを気を付ける 実行結果は同じ、forがdo~whileになっただけ
do~while do{ 処理 }while(条件式)
ループの中断 break → ループから抜ける continue → ループを1回スキップする
for(int j=0; j < 3; j++){ for(int i=0; i < 3; i++){ printf( "%d + %d = %d \n", i , j, i + j); } for(int j=0; j < 3; j++){ for(int i=0; i < 3; i++){ if(i + j == 1) break; printf( "%d + %d = %d \n", i , j, i + j); }
for(int j=0; j < 3; j++){ for(int i=0; i < 3; i++){ if(i + j == 1) break; printf( "%d + %d = %d \n", i , j, i + j); } for(int j=0; j < 3; j++){ for(int i=0; i < 3; i++){ if(i + j == 1) continue; printf( "%d + %d = %d \n", i , j, i + j); }
すべてのループから抜け出す場合は 以下のようにします。 for(int j=0; j < 3; j++){ for(int i=0; i < 3; i++){ if(i + j == 1) goto label; printf( "%d + %d = %d \n", i , j, i + j); } label: このようにラベル(label)を指定してgotoすることで外側のループも抜け出すことができます。ラベルの名前も変数と同じように自分で好きに命名できます。
繰り返しもC言語とJavaScriptは同じ goto文だけ気を付ける
関数群
math.hの数学関数を使う int n = abs(m); double a = fabs(x); double a = sqrt(x); 使い方 働き 意味 int n = abs(m); 整数の絶対値 n = |m| double a = fabs(x); 実数の絶対値 a = |x| double a = sqrt(x); 平方根 a = √x double a = exp(x); eの指数 a = ex double a = log(x); 自然対数 a = log x double a = log10(x); 常用対数 a = log10 x
double a = pow(x, y); double a = sin(x); double a = cos(x); 使い方 働き 意味 double a = pow(x, y); べき乗 a = xy double a = sin(x); サイン a = sin x double a = cos(x); コサイン a = cos x double a = tan(x); タンジェント a = tan x double a = ceil(x); 小数切り上げ 実数xを切り上げ double a = floor(x); 小数切り捨て 実数xを切り捨て double a = rint(x); 四捨五入 実数xを四捨五入
実行してみる① #include <stdio.h> #include <math.h> int main(void){ printf ("%d, %f \n", abs(-123), fabs(-0.123)); printf ("%f, %f \n", sqrt(2.0), exp(1.0)); printf ("%f, %f \n", log(2.7), log10(100.0)); return 0; } 絶対に必要
実行してみる② #include <stdio.h> #include <math.h> int main(void){ printf ("%f \n", pow(2,3)); printf ("sin30° = %f \n", sin(30 * 3.14 / 180)); printf ("cos60° = %f \n", cos(60 * 3.14 / 180)); printf ("tan90° = %f \n", tan(90 * 3.14 / 180)); return 0; } 気を付ける
実行してみる③ #include <stdio.h> #include <math.h> int main(void){ double a = 1234.5678; printf ("%f \n", ceil(a)); printf ("%f \n", floor(a)); printf ("%f \n", rint(a)); printf ("%d \n", (int)a); return 0; } 気を付ける
time.hの時間関数を使う 絶対に必要 NULLに気を付ける 実行すると1970年1月1日0時0分0秒から計った現在の時間を秒単位で返す #include <stdio.h> #include <time.h> int main(void){ printf ("%lld \n", time(NULL)); printf("%lld年\n", time(NULL)/60/60/24/365); return 0; } NULLに気を付ける 実行すると1970年1月1日0時0分0秒から計った現在の時間を秒単位で返す
疑似乱数rand()を使う 絶対に必要 #include <stdio.h> #include <stdlib.h> int main(void){ printf ("%d \n", rand()); printf ("%d \n", rand()%10 + 1); return 0; } 絶対に必要
あれれ? おかしいな… #include <stdio.h> #include <stdlib.h> あれれ? おかしいな… #include <stdio.h> #include <stdlib.h> int main(void){ for(int i=0; i < 10; i++) printf ("%d \n", rand()%10 + 1); return 0; } 何度も実行してみるとすべて結果が同じ(F5を連打してみる)
乱数表を再設定するsrand() 追加する #include <stdio.h> #include <stdlib.h> #include <time.h> int main(void){ srand(time(NULL)); for(int i=0; i < 10; i++) printf ("%d \n", rand()%10 + 1); return 0; } 追加する 何度実行してもランダム!
復習はここまで
5.プログラミング応用 ファイル操作 まとめ
前回のファイル操作 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main(void) { FILE *fp; fp = fopen("text.txt", "w"); fclose(fp); return 0; } ファイルポインタ ファイルオープン ファイルクローズ
fopen関数の意味 fp = fopen("text.txt", "w"); ファイルポインタ モード 「*」はつけない ファイル名
モードとは? r r+ w w+ a a+ モードの文字列 目的 ファイルがないとき 読み込み 失敗 読み書き 書き込み 空ファイルを作る 追加書き込み ないときだけ作る a+
では、空ファイルはどこに つくられるのか?
新しくプロジェクトを作ったとき そのままにしていれば ここにプロジェクトができる
そこに行ってみると 今までつくった プロジェクトがある
実行すると プロジェクト名のフォルダ プロジェクト名のフォルダに入っている
text.txtファイルを メモ帳などで開く なにか文字を書いて保存して 閉じる
textというテキストファイルに変数stの値が上書きされる printfのように使える #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main(void) { char st[] = "def"; FILE *fp; fp = fopen("text.txt", "w"); fprintf(fp, "%s", st); fclose(fp); return 0; } textというテキストファイルに変数stの値が上書きされる
追加する場合はモードをaにする #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main(void) { char st[] = "def"; FILE *fp; fp = fopen("text.txt", "a"); fprintf(fp, "%s", st); fclose(fp); return 0; }
読み取りread 読み取る文字の個数分宣言する readのrにする ファイルがないときの処理を書く scanf_sのように 使える #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main(void) { char st[20]; FILE *fp; fp = fopen("text.txt", "r"); if(fp == NULL) return 0; fscanf(fp, "%s", st); fclose(fp); printf("%s \n", st); } 読み取る文字の個数分宣言する readのrにする ファイルがないときの処理を書く scanf_sのように 使える
#define _CRT_SECURE_NO_WARNINGS を使わないやり方(書き込み) #include <stdio.h> int main(void) { char st[] = "def"; FILE *fp; fopen_s(&fp, "text.txt", "w"); fprintf_s(fp, "%s", st); fclose(fp); return 0; }
#define _CRT_SECURE_NO_WARNINGS を使わないやり方(追加) #include <stdio.h> int main(void) { char st[] = "def"; FILE *fp; fopen_s(&fp, "text.txt", "a"); fprintf_s(fp, "%s", st); fclose(fp); return 0; }
#define _CRT_SECURE_NO_WARNINGS を使わないやり方(読み取り) #include <stdio.h> int main(void) { char st[20]; FILE* fp; fopen_s(&fp, "text.txt", "r"); if (fp == NULL) return 0; fscanf_s(fp, "%s", st, 20); fclose(fp); printf("%s \n", st); } 読み取る文字の個数分宣言する
何かソフトウェアで作ったデータを保存したもの ファイルとは? 何かソフトウェアで作ったデータを保存したもの C言語では それだけとは限らない
ファイルの種類 テキストファイル 人間がわかるようなルールで記録してあるファイル バイナリファイル 意味不明のデータの羅列 コンパイル
ファイルの種類の例 テキストファイル バイナリファイル 文字として読めるもの 文字として読めないもの (ソースコードやHTMLなど) (機械語のプログラムや画像データなど)
CSVファイル 「カンマで値を区切ったもの」が入っている ファイル Excelなどの表計算ソフトやAccessなどのデー タベースソフトに取り込んで使用できる オープンデータなどのWebサービスで使われ ることが多い
CSVファイル書き出し 「コンマ」で区切ることでExcelで開くことができる #include <stdio.h> int main(void) { FILE* fp; char fname[] = "comma.csv"; char s1[] = "test01", s2[] = "test02", s3[] = "test03"; int n1 = 10, n2 = 20, n3 = 30; float f1 = 1.0, f2 = 2.0, f3 = 3.0; fopen_s(&fp, fname, "w"); fprintf_s(fp, "%s,%d,%f,\n", s1, n1, f1); fprintf_s(fp, "%s,%d,%f,\n", s2, n2, f2); fprintf_s(fp, "%s,%d,%f,\n", s3, n3, f3); fclose(fp); return 0; } 「コンマ」で区切ることでExcelで開くことができる
バイナリファイル操作
バイナリファイルの読み書き テキストファイルの場合は、関数が自動的に改行などを認識していたが、バイナリでは制御コードなど関係なく、同等のデータとして扱う。 "Hello" テキスト バイナリ バッファ (メモリ領域) H e l o \n \0 文字列 同じデータ
バイナリファイルを開く FILE *fp; fopen_s(&fp, "file.dat", "rb"); 拡張子は なんでも良い ファイルポインタ モード バイナリの場合はbを追記する ファイル名 rb 読み出し wb 書き込み ab 追加書き込み 拡張子は なんでも良い
バイナリファイルの開閉 #include <stdio.h> int main(void) { FILE* fp; fopen_s(&fp, "text.dat", "wb"); fclose(fp); return 0; }
バイナリファイルの書き込み #include <stdio.h> int main(void) { int buf = 100; FILE* fp; fopen_s(&fp, "text.dat", "wb"); fwrite(&buf, sizeof(int), 1, fp); fclose(fp); return 0; } バイナリで100を書き込み ファイルをメモ帳などで開くと、変な表示になっている バイナリエディタを使うと64と表示される
バッファを書き出す fwrite(&buf, sizeof(int), 1, fp); バッファの 先頭アドレス 書き出しの回数 書き出しの基本単位 (バイト) ファイル ポインタ
配列で書き出し #include <stdio.h> int main(void) { int buf[] = { 10, 100, 1000, 1000 }; FILE* fp; fopen_s(&fp, "text.dat", "wb"); fwrite(buf, sizeof(int), 4, fp); fclose(fp); return 0; } 配列に注意
バイナリファイルの読み込み バイナリファイルの1番目を読み込み 10が表示される #include <stdio.h> int main(void) { int buf; FILE* fp; fopen_s(&fp, "text.dat", "rb"); fread(&buf, sizeof(int), 1, fp); if (fp == NULL) return 0; fclose(fp); printf("%d \n", buf); } バイナリファイルの1番目を読み込み 10が表示される
配列の読み込み #include <stdio.h> int main(void) { int buf[4]; FILE* fp; fopen_s(&fp, "text.dat", "rb"); fread(buf, sizeof(int), 4, fp); if (fp == NULL) return 0; fclose(fp); for (int i = 0; i < 4; i++) printf("%d \n", buf[i]); } 配列に注意
ポインタの話を簡単に
アドレス(ポインタ値) 変数や配列はコンピュータのメモリ上にある メモリにはアドレス(ポインタ値)という連続し た番号がついている メモリのアドレス(ポインタ値)に何が入ってい るか管理できるようになっている
アドレス(ポインタ値)とは a b アドレス (ポインタ値) 1マスで1バイト E000 E001 E002 E003 E004 E005 char b short E000 E001 E002 E003 E004 E005 E006 E011 E012 E013 E014 E015 E016 アドレス (ポインタ値) 1マスで1バイト
アドレスの表し方 &a &a = 0xE001 &b = 0xE004 a 例 E001 E002 E003 E011 E012 E013 char &a E001 E002 E003 E011 E012 E013 例 &a = 0xE001 &b = 0xE004
実行してみる① #include <stdio.h> int main(void){ char a; short b; printf("aのアドレスは%p \n", &a); printf("bのアドレスは%p \n", &b); return 0; } %xにしてもよい
実行してみる② #include <stdio.h> int main(void) { int a; double b; printf("aのアドレスは%x \n", &a); printf("bのアドレスは%x \n", &b); return 0; } 何バイトになってもアドレスは先頭
実行してみる③ #include <stdio.h> int main(void) { int i1, i2, i3; printf("i1のアドレスは%p \n", &i1); printf("i2のアドレスは%p \n", &i2); printf("i3のアドレスは%p \n", &i3); return 0; }
実行してみる④ 配列の配列名はアドレス(ポインタ値)になる #include <stdio.h> int main(void) { int a[3]; printf("配列のアドレスは%p \n", a); printf("a0のアドレスは%p \n", &a[0]); printf("a1のアドレスは%p \n", &a[1]); printf("a2のアドレスは%p \n", &a[2]); return 0; } 配列の配列名はアドレス(ポインタ値)になる
実行してみる① scanf_s() #include <stdio.h> int main(void) { int a; printf("整数を入力してください\n"); scanf_s("%d", &a); printf("入力した整数は%dです \n", a); return 0; } &をつける
実行してみる② scanf_s() #include <stdio.h> int main(void) { char s[30]; printf("文字列を入力してください\n"); scanf_s("%s", s, 30); printf("入力した文字列は%sです \n", s); return 0; } &をつけない
実行してみる③ scanf_s() #include <stdio.h> int main(void) { int a, b, c; printf("整数を入力してください\n"); scanf_s("%d", &a); scanf_s("%d", &b); c = a+ b; printf("%d + %d = %d \n", a, b, c); return 0; }
配列名は先頭要素のアドレスになるため&がいらない scanf_s()の概要 例① 例② int a; scanf_s("%d", &a); char s[30]; scanf_s("%s", s, 30); データの書式 データの書式 データの格納先のアドレス 配列名は先頭要素のアドレスになるため&がいらない
数当てゲーム #include <stdio.h> int main(void) { int a=NULL, b = 7; printf("数当てゲーム!0~9の数字を入力してね\n"); while (a != b) { scanf_s("%d", &a); if (a > b) printf("もっと小さい数です\n"); else if (a < b) printf("もっと大きい数です\n"); } printf("正解です!おめでとう! \n"); return 0;
ポインタ変数 変数などが格納されている位置(アドレス)を 値とする変数をポインタ変数という。 アドレスを記憶することできる変数 ポインタ変数は「型 *変数名」の形式で宣言 する
ポインタ変数を宣言する ポインタpの宣言 空白 (スペース) char *p char* p または どちらも同じ意味!
char *p char* p あるようでないような違い 結局、どちらも同じ意味!! char 型でポインタ変数pを宣言する
実行してみる① #include <stdio.h> int main(void){ char a; char *p; p = &a; printf("aのアドレスは%p \n", p); return 0; } ポインタ変数で宣言した変数は アドレス(ポインタ値)しか代入できない
実行してみる② #include <stdio.h> int main(void){ int *p, i; p = &i; printf("pは%p \n", p); printf("&iは%p \n", &i); return 0; }
ポインタ変数 = &a アドレス(ポインタ値) *p a ポインタ変数p E001 E002 E003 E011 E012 E013 char a char ポインタ変数p E001 E002 E003 E011 E012 E013
実行してみる #include <stdio.h> int main(void) { char a; char *p; p = &a; printf("aのアドレスは%p \n", p); printf("*pのアドレスは%p \n", &p); return 0; } 違いを理解する
「*」には2つのモードがある 全く別の意味の* ・・・ ・・・ 例 例 char *p; int *i; y = *p; *p = 10; モード1: charやintの型で使うとき モード2: 処理や式の中で使うとき
実行してみる① #include <stdio.h> int main(void) { char a = 3; char *p = &a; char b = *p; printf("aのアドレスは%p \n", p); printf("*pの中の値は%d \n", *p); printf("bの中の値も%d \n", b); return 0; }
ポインタが指し示す値の参照 char a = 3; char *p; p = &a; char b = *p; *p p 3 3 = &a E001 E002 E003 &a E011 E012 E013
実行してみる② #include <stdio.h> int main(void) { char x = 4, y; char *p = &x; y = *p; printf("変数yの値は%d \n", y); return 0; }
実行してみる③ #include <stdio.h> int main(void) { int *p, i; p = &i; *p = 10; printf("*p = %d \n", *p); printf(" i = %d \n", i); printf(" &i = %x \n", &i); printf(" &*p = %x \n", &*p); return 0; }
「int *p」と「p = &a」と「*p = 10」 の違いを気を付ける! それぞれの処理の違いを明確にすること
今週はここまで 何か質問はありませんか?