Download : sample-001.c
/* * 2019/12/20 sample-001.c */ /* * */ #include <stdio.h> /* * */ int main ( int ac, char *av[] ) { int stack[1000]; /* 配列サイズは適当(充分に大きく取ってあると *仮定*) */ int stack_pointer; /* sp */ int data; /* データ */ /* 「スタック」の設計方針 「スタック」は、「下から上に積む」物として考える 「スタックポインター(sp)」は、「次にデータを積む場所」と考える ... +-----------+ 2 | | +-----------+ 1 | | +-----------+ 0 | | <- sp (stack_pointer) == 0 --------+-----------+----- */ /* * スタックを利用する前に、スタックの初期化を行う */ stack_pointer = 0; /* 初期状態では、空 (sp == 0) */ /* * 最初にスタックに 100 を積む : push ( 100 ) */ data = 100; /* データは 100 */ printf ( "スタックに %d を積みます。\n", data ); stack [ stack_pointer ] = data; /* 現在の場所にデータを保存 */ stack_pointer = stack_pointer + 1; /* スタックポインターは「次」を指す */ /* データは「現在の場所」に保存され、 sp が「次の場所」を指すようになる ... +-----------+ 2 | | +-----------+ 1 | | <- sp (stack_pointer) == 1 +-----------+ 0 | 100 | スタックトップには 100 が入る --------+-----------+----- */ /* * スタックに 123 を積む : push ( 123 ) */ data = 123; printf ( "スタックに %d を積みます。\n", data ); stack [ stack_pointer ] = data; stack_pointer = stack_pointer + 1; /* ... +-----------+ 2 | | <- sp (stack_pointer) == 2 +-----------+ 1 | 123 | スタックトップには 123 が入る +-----------+ 0 | 100 | --------+-----------+----- */ /* * スタックに 999 を積む : push ( 999 ) */ data = 999; printf ( "スタックに %d を積みます。\n", data ); stack [ stack_pointer ] = data; stack_pointer = stack_pointer + 1; /* ... +-----------+ 3 | | <- sp (stack_pointer) == 3 +-----------+ 2 | 999 | スタックトップには 999 が入る +-----------+ 1 | 123 | +-----------+ 0 | 100 | --------+-----------+----- */ /* * スタックからデータを取り出す : pop() => 999 が取り出される */ stack_pointer = stack_pointer - 1; /* まず、sp を戻す */ data = stack [ stack_pointer ]; /* sp が指す先がスタックトップ */ printf ( "スタックから取出したデータは %d です。\n", data ); /* ... +-----------+ 3 | | +-----------+ 2 | 999 | <- sp (stack_pointer) == 2 +-----------+ 1 | 123 | +-----------+ 0 | 100 | --------+-----------+----- */ /* * もう一度スタックからデータを取り出す : pop() => 123 が取り出される */ stack_pointer = stack_pointer - 1; data = stack [ stack_pointer ]; printf ( "スタックから取出したデータは %d です。\n", data ); /* ... +-----------+ 3 | | +-----------+ 2 | 999 | <- データは消えない(が、利用禁止 !!) +-----------+ 1 | 123 | <- sp (stack_pointer) == 1 +-----------+ 0 | 100 | --------+-----------+----- */ /* * スタックに 876 を積む : push ( 876 ) */ data = 876; printf ( "スタックに %d を積みます。\n", data ); stack [ stack_pointer ] = data; stack_pointer = stack_pointer + 1; /* ... +-----------+ 3 | | +-----------+ 2 | 999 | <- sp (stack_pointer) == 2 +-----------+ 1 | 876 | <- データは上書き(領域は再利用) +-----------+ 0 | 100 | --------+-----------+----- */ /* * スタックからデータを取り出す : pop() => 876 が取り出される */ stack_pointer = stack_pointer - 1; data = stack [ stack_pointer ]; printf ( "スタックから取出したデータは %d です。\n", data ); /* ... +-----------+ 3 | | +-----------+ 2 | 999 | +-----------+ 1 | 876 | <- sp (stack_pointer) == 1 +-----------+ 0 | 100 | --------+-----------+----- */ /* * スタックからデータを取り出す : pop() => 100 が取り出される */ stack_pointer = stack_pointer - 1; data = stack [ stack_pointer ]; printf ( "スタックから取出したデータは %d です。\n", data ); /* ... +-----------+ 3 | | +-----------+ 2 | 999 | +-----------+ 1 | 876 | +-----------+ 0 | 100 | <- sp (stack_pointer) == 0 : 空っぽ --------+-----------+----- */ return 0; } /* * */
$ ./sample-001.exe スタックに 100 を積みます。 スタックに 123 を積みます。 スタックに 999 を積みます。 スタックから取出したデータは 999 です。 スタックから取出したデータは 123 です。 スタックに 876 を積みます。 スタックから取出したデータは 876 です。 スタックから取出したデータは 100 です。 $
Download : sample-002.c
/* * 2019/12/20 sample-002.c */ /* * */ #include <stdio.h> /* * */ #include "int_stack.h" /* * */ void push_and_print ( IntStack *isp, int data ) { printf ( "スタックに %d を積みます。\n", data ); push_int_stack ( isp, data ); /* data を push */ } /* * */ int pop_and_print ( IntStack *isp ) { int data; data = pop_int_stack ( isp ); /* data を pop */ printf ( "スタックから取出したデータは %d です。\n", data ); return data; } /* * */ int main ( int ac, char *av[] ) { IntStack stack; /* スタックの宣言 */ /* * スタックを利用する前に、スタックの初期化を行う */ clear_int_stack ( &stack ); /* ポインターを渡す */ /* 「スタック」の設計方針 「スタック」は、「下から上に積む」物として考える 「スタックポインター(sp)」は、「次にデータを積む場所」と考える ... +-----------+ 2 | | +-----------+ 1 | | +-----------+ 0 | | <- sp (stack_pointer) == 0 --------+-----------+----- */ /* * 最初にスタックに 100 を積む : push ( 100 ) */ push_and_print ( &stack, 100 ); /* データは「現在の場所」に保存され、 sp が「次の場所」を指すようになる ... +-----------+ 2 | | +-----------+ 1 | | <- sp (stack_pointer) == 1 +-----------+ 0 | 100 | スタックトップには 100 が入る --------+-----------+----- */ /* * スタックに 123 を積む : push ( 123 ) */ push_and_print ( &stack, 123 ); /* ... +-----------+ 2 | | <- sp (stack_pointer) == 2 +-----------+ 1 | 123 | スタックトップには 123 が入る +-----------+ 0 | 100 | --------+-----------+----- */ /* * スタックに 999 を積む : push ( 999 ) */ push_and_print ( &stack, 999 ); /* ... +-----------+ 3 | | <- sp (stack_pointer) == 3 +-----------+ 2 | 999 | スタックトップには 999 が入る +-----------+ 1 | 123 | +-----------+ 0 | 100 | --------+-----------+----- */ /* * スタックからデータを取り出す : pop() => 999 が取り出される */ pop_and_print ( &stack ); /* ... +-----------+ 3 | | +-----------+ 2 | 999 | <- sp (stack_pointer) == 2 +-----------+ 1 | 123 | +-----------+ 0 | 100 | --------+-----------+----- */ /* * もう一度スタックからデータを取り出す : pop() => 123 が取り出される */ pop_and_print ( &stack ); /* ... +-----------+ 3 | | +-----------+ 2 | 999 | <- データは消えない(が、利用禁止 !!) +-----------+ 1 | 123 | <- sp (stack_pointer) == 1 +-----------+ 0 | 100 | --------+-----------+----- */ /* * スタックに 876 を積む : push ( 876 ) */ push_and_print ( &stack, 876 ); /* ... +-----------+ 3 | | +-----------+ 2 | 999 | <- sp (stack_pointer) == 2 +-----------+ 1 | 876 | <- データは上書き(領域は再利用) +-----------+ 0 | 100 | --------+-----------+----- */ /* * スタックからデータを取り出す : pop() => 876 が取り出される */ pop_and_print ( &stack ); /* ... +-----------+ 3 | | +-----------+ 2 | 999 | +-----------+ 1 | 876 | <- sp (stack_pointer) == 1 +-----------+ 0 | 100 | --------+-----------+----- */ /* * スタックからデータを取り出す : pop() => 100 が取り出される */ pop_and_print ( &stack ); /* ... +-----------+ 3 | | +-----------+ 2 | 999 | +-----------+ 1 | 876 | +-----------+ 0 | 100 | <- sp (stack_pointer) == 0 : 空っぽ --------+-----------+----- */ return 0; } /* * */
$ ./sample-002.exe スタックに 100 を積みます。 スタックに 123 を積みます。 スタックに 999 を積みます。 スタックから取出したデータは 999 です。 スタックから取出したデータは 123 です。 スタックに 876 を積みます。 スタックから取出したデータは 876 です。 スタックから取出したデータは 100 です。 $
Download : sample-003.c
/* * 2019/12/20 sample-003.c */ /* * */ #include <stdio.h> #include "s_print.h" #include "s_input.h" /* * */ #define EOS '\0' /* * 複数の整数を書式指定して文字列の中に埋め込む */ void print_with_format ( char *msg, ... ) { int i; char *pvalue = (char *)&msg + sizeof( char * ); for ( i = 0; msg[i] != EOS; i++ ) { if ( msg[i] == '%' ) { /* 文字列の中に '%' があったら特別処理する */ i++; /* 次の文字をみる */ switch ( msg[i] ) { case 'd': /* 10 進数 */ s_print_int ( *((int *)pvalue) ); // s_print_int ( *pvalue++ ); pvalue += sizeof ( int ); break; case 'o': /* 8 進数 */ s_print_int ( *((int *)pvalue) ); pvalue += sizeof ( int ); break; case 'x': /* 16 進数 */ s_print_int ( *((int *)pvalue) ); pvalue += sizeof ( int ); break; case 'c': /* 文字 */ s_print_char ( *((char *)pvalue) ); pvalue += sizeof ( int ); /* char は自動的に int にされる */ break; case 's': /* 文字列 */ s_print_string ( *((char **)pvalue) ); pvalue += sizeof ( char * ); break; case 'f': /* 浮動小数点数 */ s_print_double ( *((double *)pvalue) ); pvalue += sizeof ( double ); break; case '%': /* '%' が重なったら.. */ s_print_char ( '%' ); /* '%' を出力 */ break; default: /* その他 : よくわからないので読み飛ばす.. */ break; } } else { /* そうでなけれ .. */ s_print_char ( msg[i] ); /* そのままその文字を出力 */ } } } /* * 色々な数値の出力 */ int main ( void ) { /* * データの出力 (Output) */ print_with_format ( "整数値(%%d) : %d, 文字(%%c) : '%c', 文字列(%%s) : \"%s\", 浮動小数点数(%%f) : %f\n", 123, (int)'a', "xyz", 1.23 ); /* * */ return 0; } /* * */
$ ./sample-003.exe 整数値(%d) : 1, 文字(%c) : '%', 文字列(%s) : "h`?D?", 浮動小数点数(%f) : 0.000000 $
Download : sample-004.c
/* * 2019/12/20 sample-004.c */ #include <stdio.h> #include <math.h> /* * cf. http://www.asahi-net.or.jp/~uc3k-ymd/Lesson/Section01/section01_06.html */ // 10進→2進へ変換して出力 void dec2bin(double x, int bit[]) { // ビット演算は、整数型または文字型に対して使用しなければならないので、 // 共用体を使って浮動小数点型のデータを文字型(整数型)として参照する union { double d; // 8バイト(64ビット)の領域 unsigned char c[8]; } data; data.d = x; //double型で代入 int i,j, k = 0; for(i=7; i >= 0; i--) {// 文字型で1バイトごとに取り出す unsigned char ch = data.c[i]; for(j = 7; j >= 0; j--){ // 1バイト単位で2進数に変換を行う if( (ch >> j) & 1 ) { bit[k] = 1; } else { bit[k] = 0; } // ビットを出力 putchar ( '0' + bit[k] ); k++; } putchar ( ' ' ); // 1バイトごとに区切りを入れる } putchar ( '\n' ); } // 仮数部と指数部を2進→10進へ変換して出力する void bin2dec(int bit[]) { int BIAS = 1023; // 指数バイアス // 指数部は0〜2047の値で表されている、この値から // BIASを引くことで、-1023〜1024の範囲で本当の値が求まる int exponent=0; // 指数部 double fraction=0.0; // 仮数部の小数点以下 int sign = 1 - 2*bit[0]; //符号ビット0:正、1:負なので // 0 -> 1 1 -> -1 となる // 指数部を10進整数に変換 int i; for (i=11; i>=1; i--) {// 指数部は11ビット exponent += (int)(bit[i]*pow(2, 11-i)); } // 仮数部を10進小数に変換 for (i=12; i<=63; i++) {// 仮数部は52ビット fraction += bit[i]*pow(2, 11-i); } printf ( "%f ×2^%d\n", sign * (1.0 + fraction), (exponent - BIAS) ); } int main(void) { int bit[64]; // ビットパターンを格納する double x; printf ( "実数値を入力して下さい: " ); scanf ( "%lf", &x ); printf ( "\ndouble型の入力データの内部表現(2進数表示)\n\n" " [指数部 ][ ---- 仮数部 ----- ]\n" ); dec2bin(x, bit);// 10進→2進へ変換しbit[]に格納する printf ( "\n入力データ: %f = ", x ); bin2dec(bit);// 仮数部と指数部の2進→10進へ変換 return 0; }
0.1
$ ./sample-004.exe < sample-004.in 実数値を入力して下さい: 0.100000 double型の入力データの内部表現(2進数表示) [指数部 ][ ---- 仮数部 ----- ] 00111111 10111001 10011001 10011001 10011001 10011001 10011001 10011010 入力データ: 0.100000 = 1.600000 ×2^-4 $
#include <stdio.h> /* p-001.c の中身を画面に出力する */ int main(int argc, char *argv[]) { FILE *fp; /* ファイルポインタの宣言 */ /* 「FILE *」型は実際のファイルと結びついて、 そのファイルへの入出力の窓口になる */ int ch; /* 読みこむ文字 */ fp = fopen ( "p-001.c", "r" ); /* ファイル「p-001.c」を"r" (Read:読み込みモード)で「開く」*/ ch = fgetc ( fp ); /* ファイルポインタ fp を経由して「1 文字」読みだす */ while ( ch != EOF ) { /* もし、最後まで読みこんだ後の場合は EOF が返る */ putchar ( ch ); /* その文字を出力し .. */ ch = fgetc ( fp ); /* 次の文字を読みだす */ } fclose ( fp ); /* ファイルを使い終わったら、それ「閉じる」*/ return 0; }
#include <stdio.h> /* p-002.out にキーボードからの入力を保存する */ int main(int argc, char *argv[]) { FILE *fp; /* ファイルポインタの宣言 */ /* 「FILE *」型は実際のファイルと結びついて、 そのファイルへの入出力の窓口になる */ int ch; /* 読みこむ文字 */ fp = fopen ( "p-002.out", "w" ); /* ファイル「p-002.out」を"w" (Write:書き出しモード)で「開く」*/ ch = getchar(); /* キーボードから「1 文字」読みだす */ while ( ch != EOF ) { /* もし、Ctrl-D が入力された場合は EOF が返る */ /* キーボード入力の終了は、Unix(Linux:Ubuntu) 場合は Ctrl-D */ /* Windows の場合は Ctrl-Z となる */ fputc ( ch, fp ); /* その文字を書き出し .. */ ch = getchar(); /* 次の文字を読みだす */ } fclose ( fp ); /* ファイルを使い終わったら、それ「閉じる」*/ return 0; }
#include <stdio.h> /* p-002.out にキーボードからの入力を追加する */ int main(int argc, char *argv[]) { FILE *fp; /* ファイルポインタの宣言 */ /* 「FILE *」型は実際のファイルと結びついて、 そのファイルへの入出力の窓口になる */ int ch; /* 読みこむ文字 */ fp = fopen ( "p-002.out", "a" ); /* ファイル「p-002.out」を"a" (Append:追記モード)で「開く」*/ ch = getchar(); /* キーボードから「1 文字」読みだす */ while ( ch != EOF ) { /* もし、Ctrl-D が入力された場合は EOF が返る */ /* キーボード入力の終了は、Unix(Linux:Ubuntu) 場合は Ctrl-D */ /* Windows の場合は Ctrl-Z となる */ fputc ( ch, fp ); /* その文字を書き出し .. */ ch = getchar(); /* 次の文字を読みだす */ } fclose ( fp ); /* ファイルを使い終わったら、それ「閉じる」*/ return 0; }
#include <stdio.h> /* p-002.out の先頭から、5 byte 目にキーボードからの入力を記録する */ int main(int argc, char *argv[]) { FILE *fp; /* ファイルポインタの宣言 */ /* 「FILE *」型は実際のファイルと結びついて、 そのファイルへの入出力の窓口になる */ int ch; /* 読みこむ文字 */ fp = fopen ( "p-002.out", "r+" ); /* ファイル「p-002.out」を"a+" (書き込みだがシーク可能)で「開く」*/ fseek ( fp, 5L, SEEK_SET ); /* 書き込み位置を、ファイルの先頭(SEEK_SET)から、5 byte 目(5L)の場所に移動 */ ch = getchar(); /* キーボードから「1 文字」読みだす */ while ( ch != EOF ) { /* もし、Ctrl-D が入力された場合は EOF が返る */ /* キーボード入力の終了は、Unix(Linux:Ubuntu) 場合は Ctrl-D */ /* Windows の場合は Ctrl-Z となる */ fputc ( ch, fp ); /* その文字を書き出し .. */ ch = getchar(); /* 次の文字を読みだす */ } fclose ( fp ); /* ファイルを使い終わったら、それ「閉じる」*/ return 0; }
#include <stdio.h> typedef struct { int x; int y; int z; } Point3D; void printPoint3D ( Point3D pt ) { printf ( "(%d, %d, %d)\n", pt.x, pt.y, pt.z ); } void modifyX ( Point3D *ptp, int newX ) { (*ptp).x = newX; /* ptp が指す構造体の x を書き換える */ /* 構造体の性質[タグ名を利用して要素が参照できる] */ /* ポインタ値の性質 */ } void modifyY ( Point3D *ptp, int newY ) { ptp -> y = newY; /* ptp -> y <=> (*ptp).y は同じ */ } int main(int argc, char *argv[]) { Point3D pt; pt.x = 1; pt.y = 2; pt.z = 3; printPoint3D ( pt ); modifyX ( &pt, 100 ); /* 構造体の x 要素を 100 に変更 */ /* ポインターを渡す事により、呼び出し先で、 呼び出し元の変数の値が変更できる */ printPoint3D ( pt ); modifyY ( &pt, 200 ); printPoint3D ( pt ); return 0; }
#include <stdio.h> #define EOS '\0' int main(int argc, char *argv[]) { char string[100]; /* サイズ 100 なので、 99 (=100-1[EOS]) までの長さ */ string[0] = 'a'; string[1] = 'b'; string[2] = 'c'; string[3] = EOS; /* string <-> "abc" と同じように扱われる */ /* string[4] ? string[99] の内容は無視される */ string[4] = 'Z'; printf ( "%s\n", string ); /* 文字配列を「文字列」として扱う */ string[3] = '1'; string[5] = EOS; printf ( "%s\n", string ); return 0; }
#include <stdio.h> #include <malloc.h> /* 文字「リスト」 Linked List の形で実装 "abc" +-------+ +-------+ +-------+ | *-----> | *-----> |NULL | +-------+ +-------+ +-------+ | 'a' | | 'b' | | 'c' | +-------+ +-------+ +-------+ */ typedef struct cell { struct cell *next; char charactor; } Cell; /* Cell <-> struct cell */ Cell *make_Cell( Cell *next_, int charactor_ ) { Cell *cellp = malloc ( sizeof( Cell ) ); if ( cellp != NULL ) { cellp -> next = next_; cellp -> charactor = charactor_; } return cellp; } void print_Cell ( Cell *cellp ) { if ( cellp != NULL ) { putchar ( cellp -> charactor ); print_Cell ( cellp -> next ); } } void append_charctor ( Cell *cellp, char append ) { Cell *prev = NULL; while ( cellp != NULL ) { prev = cellp; cellp = cellp -> next; } /* prev は、最初に引数で指定された文字リストの最後を指す */ if ( prev != NULL ) { prev -> next = make_Cell ( NULL, append ); /* 最後の要素に、次の文字を追加する */ } } Cell *insert_charctor ( Cell *cellp, char insert ) { return make_Cell ( cellp, insert ); } void delete_second_char ( Cell *cellp ) { Cell *remove = NULL; /* NULL は、「存在するもの」と一致しない事が保証されている */ if ( cellp != NULL ) { /* ポインタ値は、NULL の可能性があるので必ずチェック */ remove = cellp -> next; /* 二文字目 */ cellp -> next = remove -> next; /* 二文字目のセルが切り離される */ free ( remove ); /* 二文字目を保持するセルが不要なので free */ } } void all_Cell_free ( Cell *ptr ) { if ( ptr != NULL ) { /* もし、NULL でなければ */ all_Cell_free ( ptr -> next ); /* 最初に後ろを開放して */ free ( ptr ); /* 後で、自分自身を開放 */ /* 順番は、重要 */ } } int main(int argc, char *argv[] ) { Cell *ptr = make_Cell ( make_Cell ( make_Cell ( NULL, 'c' ), 'b' ), 'a' ); print_Cell ( ptr ); printf ( "\n" ); append_charctor ( ptr, 'z' ); print_Cell ( ptr ); printf ( "\n" ); ptr = insert_charctor ( ptr, '@' ); print_Cell ( ptr ); printf ( "\n" ); delete_second_char ( ptr ); print_Cell ( ptr ); printf ( "\n" ); all_Cell_free ( ptr ); /* 最後に必ず、alloc したメモリは free する */ return 0; }
#include <stdio.h> void sub( int ary[][4] ) { /* 最初の一つの添え字は省略可能だが、それ以外は必要 */ /* why ? &ary[0] = ary &ary[1] = ary + 1 -> 番地は、sizeof ( int[4] だけ変化するする必要がある ) 後ろの[4] の情報がないと、計算できない 一般に、多次元配列を、関数の引数に渡す場合は、 最初の添え字のサイズだけ、省略可能 */ } int main(int argc, char *argv[]) { int ida[3][4]; /* 二次元配列 */ /* サイズが 4 の(一次元配列)が、3 個並んでいる */ /* int ida[3][4]; 3 行 4 列の行列 => int ida0[4] int ida1[4] ind ida2[4] */ /* 数学の行列(Matrix) は、二次元配列で表現できる cf. 今 Deep Learing (AI) で、利用されている TesorFlow というツールの名前一部である Tesor : 多次元配列の事 */ int i; int j; int *pi; for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 4; j++ ) { ida[i][j] = i * 10 + j; } } for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 4; j++ ) { printf ( "ida[%d][%d] = %d\n", i, j, ida[i][j] ); } } for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 4; j++ ) { printf ( "&ida[%d][%d] = %p\n", i, j, &ida[i][j] ); } } pi = (int *) ida; for ( i = 0; i < 4 * 3; i++ ) { printf ( "pi[%d] = %d\n", i, pi[i] ); } /* 特に.. */ /* ida[n] -> &ida[n][0] */ /* ida[n][0] <-> *(ida[n]+0) */ /* &ida[n][0] <-> &*(ida[n]+0) */ /* &ida[n][0] <-> ida[n] */ sub ( ida ); /* 渡されるのは、メモリモデルの番地番号 */ return 0; }
前回(2019/12/20)の内容 ファイル I/O C 言語でファイルの内容を扱う「標準ライブラリ」の使い方 「標準ライブラリ」 C 言語の一部ではないが、C 言語が利用できる環境では、 同一の利用法で、同一の効果が得られる事が保証された形で提供される 「C 言語の『移植性』」を担保する役割を担っている cf. 環境(OS)が異なれば、「同じ役割を持つもの」が「同じに使える」保証がない => もし、「異なる環境では異なるプログラム必要」なら、大変 <= しかし、「その違いを吸収するもの」があれば、 同じプログラムを異なる環境で、「そのまま」利用できる可能性がある => プログラムの移植性 <= プログラミング言語が、なんらかのサービスを提供する必要がある C 言語の場合は、「標準ライブラリ」がそれを担保する !!! 特に C 言語の場合は、「ライブラリ」の比重が大きい => C 言語を活用するためには、(じつは..)標準ライブラリの活用法が不可欠 もうしわけないが、ソフトウェア概論では、そのほんの一部しか触れられない => 言語そのものより、多くの内容がある I/O 位 ( printf/scanf/fopen/fclose ) 数学関係 ( sqrt, sin, cos, etc.. ) => 他にもたくさんある => Call by Need (必要になったら調べる..) fopen でファイルを「開き」、ファイルポインタを入手 "r" で読み込み fgetc を使うと、一文字読みこまれるだけでなく、 次の文字を読みだすように、読み出し位置が一つ進む "w" で書き込み fputc を使うと、一文字書き込まれるだけでなく、 次の文字を書き込めるように、次の書き込み先位置が一つ進む # 開いた瞬間、元の内容は、すべて失われる "a" 追記 基本は、"w" と同じだけど、元のファイルの内容は失われず、 最初に書き込む先が、ファイルの最後になる "+" ランダムアクセスも可能 読みこみ場所や書き出し場所を、fseek を利用して、変更可能 fseek を利用する事により、書き出しや読み込み位置が変更 r+ ( read しつつ、書き込みなども可能なる.. ) ファイルポインタと 「f-関数」を利用して「入出力」 Input: fgetc, fscanf, fgets, ... Output: fputc, fprintf, fputs, ... fclose でファイルを「閉じ」る => これを忘れると、いろいろ厄介な事に... # 特に、書き出しの時に、fclose を忘れると、書き込み結果が保証されない可能性がある # !! windows の場合は、運が悪いと、二度と開けないファイルができたりする [落穂ひろい] 構造体のポインターアクセス 構造体へのポインタ値を利用して、その構造体の要素を参照する場合 例: Point3D *ptp;で x 要素を参照する そのポインタ値に*を付けて、かっこでかこってから、タグ名を付ける (*ptp).x とよいが、その省略記法として、-> を利用してもよい ptp -> x (復習) 動的データ型 => alloc (malloc/calloc) を利用して、実行時に、領域を確保して、データを収める 動的データ型は、「不特定多数の要素からなるデータ(を保存する領域)」を扱う型 例 : 文字列 複数の文字からなっている C 言語では、「文字列」を「文字配列」で表現する <= 「配列」そのものは、基本、静的なので、最大サイズをきめて、 その「範囲内」であつかう => 実行時に、「範囲を超えた」サイズは扱えない <= 動的なアプローチを考える 長さが長くなった時点で、それの領域を動的に確保して、追加する => 具体例 : 文字「リスト」を作る Linked List にする事により、原理的(メモリ量が許す限り..)に いくらでも長い文字列が表現できる
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20191227-01.c
/* * 20191227-01-QQQQ.c * ポインター演算子を利用して構造体を操作 */ #include <stdio.h> /* * 二次元の「点」を表す構造体型 Point2D の宣言 */ typedef struct { int x; int y; } Point2D; /* * move_to_x_axis_symmetry ( Point2D *p2dPtr ) * 指定された Point2D 型の変数へのポインターの値を x 軸に対象な点に移す * Point2D *p2dPtr : Point2D 型の変数へのポインターの値 */ void move_to_x_axis_symmetry ( Point2D *p2dPtr ) { /* x 軸に対称なので、y 座標の符号だけを変更 */ p2dPtr -> y = - p2dPtr -> y; /* y 座標の符号を逆転 */ } /* * move_to_y_axis_symmetry ( Point2D *p2dPtr ) * 指定された Point2D 型の変数へのポインターの値を y 軸に対象な点に移す * Point2D *p2dPtr : Point2D 型の変数へのポインターの値 */ void move_to_y_axis_symmetry ( Point2D *p2dPtr ) { /* y 軸に対称なので、x 座標の符号だけを変更 */ /* ** この部分を完成させなさい */ } /* * move_to_origin_symmetry ( Point2D *p2dPtr ) * 指定された Point2D 型の変数へのポインターの値を 原点に対象な点に移す * Point2D *p2dPtr : Point2D 型の変数へのポインターの値 */ void move_to_origin_symmetry ( Point2D *p2dPtr ) { /* 原点対称に移動するには、 x 軸対称に移動して、から y 軸対称に移動すればよい */ move_to_x_axis_symmetry ( p2dPtr ); /* 引数は初めからポインター値 */ /* ** この部分を完成させなさい */ } /* * print_point2d ( Point2D p2dVar ) * 指定された Point2D 型の値を表示する * Point2D p2dVar; Point2D 型の値 */ void print_point2d ( Point2D p2dVar ) { /* x, y 座標をそれぞれ出力するだけ */ printf ( "(%d, %d)", p2dVar.x, p2dVar.y ); } /* * */ int main ( void ) { Point2D Pa = { -1, 3 }; /* 座標 ( -1, 3 ) の点 Pa */ Point2D Pb = { 2, 5 }; /* 座標 ( 2, 5 ) の点 Pb */ printf ( "Pa = " ); print_point2d ( Pa ); /* Point2D の値を指定 */ printf ( "\nを、x 軸対称な位置に移動すると.." ); move_to_x_axis_symmetry ( &Pa ); /* Point2D 型の変数のポインター値を指定 */ print_point2d ( Pa ); printf ( "になります\n" ); printf ( "Pb = " ); print_point2d ( Pb ); printf ( "\nを、原点対称な位置に移動すると.." ); /* ** この部分を完成させなさい */ print_point2d ( Pb ); printf ( "になります\n" ); return 0; } /* * */
2.3 9.1 5.9 2.7 3.2
$ ./20191227-01-QQQQ.exe Pa = (-1, 3) を、x 軸対称な位置に移動すると..(-1, -3)になります Pb = (2, 5) を、原点対称な位置に移動すると..(-2, -5)になります $