/* * 20161209-02-QQQQ.c * 二つのファイルを指定して、その違いのある場所(何 byte 目か)を表示する */ #include <stdio.h> /* * main */ int main ( int argc, char *argv[] ) { /* argc -> コマンドライン引数で指定されたパラメータの個数 - 1 */ if ( argc != 3 ) { /* コマンドラインに二つのファイル名をしているかどうか をチェック */ printf ( "ファイル名を二つ指定して下さい。\n" ); } else { /* コマンドで、二つ引数が指定されており、 一つ目の引数が argv[1] 二つ目の引数が argv[2] になる ちなみに、argv[0] は、コマンド(ファイル)名 さらにちなみに、argv[argc] = argv[3] = NULL になっている */ FILE *fp1; if ( ( fp1 = fopen ( argv[1], "r" ) ) == NULL ) { /* fopen が NULL を返した場合は、何かエラーがおきている */ printf ( "ファイル(%s)を開く事ができませんでした。\n", argv[1] ); } else { FILE *fp2; if ( ( fp2 = fopen ( argv[2], "r" ) ) == NULL ) { printf ( "ファイル(%s)を開く事ができませんでした。\n", argv[2] ); } else { /* 二つともオープンができたので、先頭から比較 */ int position; /* いま比較しているのが先頭から何バイトか ? */ int ch1; /* 一つ目のファイルの文字を記録 */ int ch2; /* 二つ目のファイルの文字を記録 */ for ( position = 0; (ch1 = fgetc (fp1)) != EOF; position++ ) { ch2 = fgetc( fp2 ); if ( ch1 != ch2 ) { /* 読み込んだ文字が一致しない */ break; /* 終了 */ } } if ( ch1 == EOF ) { /* 一つ目が終わっているとき */ ch2 = fgetc( fp2 ); /* fp2 も fp1 同じところまで読む */ } if ( ch1 == ch2 ) { printf ( "二つのファイル(%s,%s)は同じ内容です。\n", argv[1], argv[2] ); } else if ( ch1 == EOF ) { /* fp2 の方がまだある */ printf ( "ファイル(%s) の方がサイズが大きいです。\n", argv[2] ); } else if ( ch2 == EOF ) { /* fp1 の方がまだある */ printf ( "ファイル(%s) の方がサイズが大きいです。\n", argv[1] ); } else { printf ( "%d byte 目で %s は %c, %s は %c という違いがありました。\n", position, argv[1], ch1, argv[2], ch2 ); } fclose ( fp2 ); /* ここなら fp2 が NULL でないことが保障されている */ } fclose ( fp1 ); /* ここなら fp1 が NULL でないことが保障されている */ } } return 0; }
/* 型情報の例 */ #include <stdio.h> int main(int argc, char *argv[] ) { printf ( "3/2=%d\n", 3 /2 ); /* 整数値の場合 */ printf ( "3.0/2.0=%f\n", 3.0/2.0 ); /* 浮動小数点数の場合 */ return 0; }
/* 型情報を操作する キャスト */ #include <stdio.h> int main(int argc, char *argv[] ) { printf ( "3/2=%d\n", 3 /2 ); /* 整数値の場合 */ printf ( "3.0/2.0=%f\n", 3.0/2.0 ); /* 浮動小数点数の場合 */ /* 値(式)の前に「(型名)」と書くと、 その値の型を、その「型名の型」に変更 してくれる この「(型名)」を「キャスト演算子」と呼び、 特定な型の値をキャスト演算子を用いて型変換する事を 「キャスト」 と呼ぶ。 # 型が変わることにより、値も変わることがある */ printf ( "(double)3/(double)2=%f\n", (double)3 /(double)2 ); /* 整数値の場合 */ printf ( "(int)3.0/(int)2.0=%d\n", (int)3.0/(int)2.0 ); /* 浮動小数点数の場合 */ /* 型が変わることにより、値も変わることがある */ printf ( "(int)1.5=%d\n", (int)1.5 ); /* 「1.5」という浮動小数点数を (int) を用いて、 整数型にキャストすると、 整数値「1」に変わる(小数点数以下が切り捨てられる) */ /* キャストはいつもできるわけではない 「文字列」を「整数」キャストする (int)"123" -> 123 (char *)123 -> "123" などは「C 言語では」できない もししたければ、それと同等なことを行う関数を利用する cf. 文字列を整数値に変更する関数は atoi である int a = atoi( "123" ); とすると、a には 整数値の 123 が入る 構造体を浮動小数点数にキャストしたりはできない */ /* キャストができるのは char <-> int <-> double # 本当は学んでいないほかの型の間でもキャスト可能 # short, long, unsigined, float どれも「数」として扱える 「キャスト」はコンパイラが実現してくれる機能 */ return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { int ivar = 123456789; int *pivar = &ivar; /* pivar ??????|?C???^?? ivar ???w?? */ /* byte pivar +-------+ ivar +-------+ | * ---------------> | 15 | +-------+ +-------+ | cd | +-------+ | 5b | +-------+ | 07 | +-------+ ivar ??? -> */ printf ( "%x\n", ivar ); /* ivar ??l(?????l)?? 16 ?i????o?? */ /* ?????w??? %x ????? */ printf ( "*(%p)=%x\n", pivar, *pivar ); /* *pivar = *(&ivar) = (*&)ivar = ivar */ /* ?????????? */ printf ( "piver + 1 = %p\n", pivar + 1 ); /* ?????A??L??l + 4 (sizeof(int)) ???? */ printf ( "*(%p)=%x\n", (char *)pivar, *(char *)pivar ); printf ( "*(%p)=%x\n", ((char *)pivar)+1, *(((char *)pivar)+1) ); /* ?????A??L??l + 1 (sizeof(char)) ???? */ printf ( "*(%p)=%x\n", ((char *)pivar)+2, *(((char *)pivar)+2) ); printf ( "*(%p)=%x\n", ((char *)pivar)+3, *(((char *)pivar)+3) ); return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { int i; int *pi = &i; /* ポインタ値のアドレス値(だけ)の変更 */ printf ( "pi=%p\n", pi ); printf ( "pi+1=%p\n", pi + 1 ); printf ( "pi-1=%p\n", pi - 1 ); /* 型情報の変更とその影響 */ printf ( "(double *)pi=%p\n", (double *)pi); printf ( "(double *)pi + 1=%p\n", ((double *)pi) + 1 ); printf ( "(double *)pi - 1=%p\n", ((double *)pi) - 1 ); printf ( "(char *)pi=%p\n", (char *)pi); printf ( "(char *)pi + 1=%p\n", ((char *)pi) + 1 ); printf ( "(char *)pi - 1=%p\n", ((char *)pi) - 1 ); return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { int ivar = 0x12345678; /* 16 進数で、整数値を指定 */ int jvar; int *pivar = &ivar; int *pjvar = &jvar; /* pivar +-------+ ivar +-------+ | * ---------------> | 78 | +-------+ +-------+ | 56 | +-------+ | 34 | +-------+ | 12 | +-------+ */ /* [Step 0] */ jvar = 0; printf ( "ivar = %d(%x)\n", ivar, ivar ); printf ( "jvar = %d(%x)\n", jvar, jvar ); /* [Step 1] */ jvar = ivar; printf ( "ivar = %d(%x)\n", ivar, ivar ); printf ( "jvar = %d(%x)\n", jvar, jvar ); /* [Step 2] */ ivar = 0x87654321; *pjvar = *pivar; /* *(&jvar) = *(&ivar) -> (*&)jvar = (*&)ivar -> jvar = ivar */ printf ( "ivar = %d(%x)\n", ivar, ivar ); printf ( "jvar = %d(%x)\n", jvar, jvar ); /* [Step 3] */ ivar = 0x12345678; /* pivar +-------+ ivar +-------+ | * ---------------> | 78 | +-------+ +-------+ | 56 | +-------+ | 34 | +-------+ | 12 | +-------+ pjvar +-------+ jvar +-------+ | * ---------------> | 12 | <- ここが 78 +-------+ +-------+ | 34 | +-------+ | 56 | +-------+ | 78 | +-------+ */ *(char *)pjvar = *(char *)pivar; printf ( "ivar = %d(%x)\n", ivar, ivar ); printf ( "jvar = %d(%x)\n", jvar, jvar ); /* ある型へのポインタ値から別の型へのポインタ値への キャストは常に可能 例 (char *) -> (int *) 型情報を書き換えているだけで、値は変更していない *(int *) "1234" は 1234 にはならない... (why ?) "1234" +------+ | '1' | +------+ | '2' | +------+ | '3' | +------+ | '4' | +------+ | '\0' | +------+ +------+ | 31 | 十六進数 +------+ | 32 | +------+ | 33 | +------+ | 34 | +------+ | '\0' | +------+ なので、 *(int *) "1234" -> 0x34333231 */ printf ( "*(int *)\"1234\"=%x\n", *(int *)"1234" ); return 0; }
#include <stdio.h> int main(int argc, char *argv[]) { int i; /* 「標準入力」から入力し */ scanf ( "%d", &i ); /* 整数値を一つ入力して */ /* 「標準出力」に出力する */ printf ( "%d\n", i + 1 ); /* その値に 1 を加えて出力する */ /* 標準入出力は、プログラムを実行する OS がきめている 通常は、標準入力が、キーボード 標準出力が、画面になっている OS がリダイレクション機能を実現しており、 これによって、標準入出力の先を切り替える(リダイレクト)できる redirect = re + direct */ return 0; }
#include <stdio.h> int main(int argc, char *argv[]) { int ch; while ( ( ch = getchar() ) != EOF ) { putchar ( ch ); } return 0; }
#include <stdio.h> /* getchar() 標準入力から一文字入力する putchar() 標準出力へ一文字出力する stdin : 標準入力 stdout ; 標準出力 を表している getchar() <-> fgetc ( stdin ) stdin から入力 scanf ( "%d", &i ); <-> fscanf ( stdin, "%d", &i ); putchar(ch) <-> fputc ( ch, stdout ) stdout へ出力 printf ( "i=%d\n", i ); <-> fprintf ( stdout, "i=%d\n", i ); */ int main(int argc, char *argv[]) { int ch; while ( ( ch = fgetc(stdin) ) != EOF ) { fputc ( ch, stdout ); } return 0; }
#include <stdio.h> /* getchar() 標準入力から一文字入力する putchar() 標準出力へ一文字出力する stdin : 標準入力 stdout ; 標準出力 を表している getchar() <-> fgetc ( stdin ) stdin から入力 scanf ( "%d", &i ); <-> fscanf ( stdin, "%d", &i ); putchar(ch) <-> fputc ( ch, stdout ) stdout へ出力 printf ( "i=%d\n", i ); <-> fprintf ( stdout, "i=%d\n", i ); */ int main(int argc, char *argv[]) { int ch; FILE *ifp = fopen ( "p-006.in", "r" ); /* ファイル p-006.in を 読み出しモード ("r") で開いて そのファイルポインタ値を返す。 変数 ifp (ファイルポインタ) の値は、 stdin と同じ様に使える */ /* ポインタ値 動的に処理されている ( 中で malloc などが利用されている ) open に失敗した場合は NULL が返るので、 NULL かどうかをチェックする必要がある free に相当する処理が必要である fclose fopen で得られる値は NULL かどうかチェックする NULL でない時には、最後に fclose する */ if ( ifp != NULL ) { FILE *ofp = fopen ( "p-006.out", "w" ); /* ファイル p-006.out を 書き出しモード ("w") で開いて そのファイルポインタ値を返す。 変数 ofp (ファイルポインタ) の値は、 stdout と同じ様に使える */ if ( ofp != NULL ) { while ( ( ch = fgetc( ifp ) ) != EOF ) { /* ファイル p-006.in から読み込んで */ fputc ( ch, ofp ); /* ファイル p-006.out に書き出す */ } fclose ( ofp ); } fclose ( ifp ); } return 0; }
#include <stdio.h> #include <malloc.h> int main(int argc, char *argv[] ) { int *pvar = (int *)malloc ( sizeof ( int ) ); /* malloc ??A??????w?????Asize byte ?? (???????A sizeof (int) = 4 ????A 4 byte) ??????m????A???????u?A?h???X?l?v???u?l?v??????? ?{????~???????A?u?|?C???^?l?v=?u?A?h???X?l?v+?u?^???v malloc ??A????A(void *) ??????^??|?C???^?l???? (void *) ??A?u?^???v??????u?????????v ????A?L???X?g????g???????{ */ /* *(malloc ( sizeof ( int ) )) = 1 *(malloc ( 4 )) = 1 ?^????????A?????????? malloc ( 4 ) -> int ?? 1 ??????A -> char ?? 4 ??????A -> double ???????????A??????? *((int *)malloc ( 4 )) = 1 -> ???????? *((char *)malloc ( 4 )) = 1 -> malloc ?? ?T?C?Y 4 ?? char ?z???A???? 0 ???? 1 ????? */ }
今週の新規追加の課題はありません。