/*
* 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 ?????
*/
}
今週の新規追加の課題はありません。