Download : sample-001.c ( SJIS 版 )
/* * 2013/12/20 sample-001.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; } /* * */
C:\usr\c>sample-001 整数値(%d) : 123, 文字(%c) : 'a', 文字列(%s) : "xyz", 浮動小数点数(%f) : \ 1.230000 C:\usr\c>
#include <stdio.h> int main(int argc, char *argv[] ) { int i; scanf ( "%d", &i ); /* キーボードから整数値を 一つ読込み、変数 i に代入 */ printf ( "i=%d\n", i ); /* 変数 i の値(キーボードから入力した値) を 表示する */ return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { printf ( "sizeof(char)=%d\n", sizeof(char) ); printf ( "sizeof(int)=%d\n", sizeof(int) ); printf ( "sizeof(double)=%d\n", sizeof(double) ); }
#include <stdio.h> int main(int argc, char *argv[] ) { int i; /* int 型なので char 型 4 つ分 */ i = 'A'; /* i に 'A' ( ASCII Code で 65 ) */ printf ( "i = %d\n", i ); /* 65 が表示される */ printf ( "&i = %s\n", &i ); /* 何がおきるか ? */ i = 'A' * 256 + 'B'; printf ( "&i = %s\n", &i ); /* 何がおきるか (2) ? */ i = ('A' * 256 + 'B') * 256 + 'C'; printf ( "&i = %s\n", &i ); /* 何がおきるか (3) ? */ return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { int i = 10; int j = 100; char a = 'a'; char b = '0'; printf ( "&i = %x\n", &i ); /* %x は整数値(アドレス値)を 16 進数で表示 */ printf ( "&j = %x\n", &j ); printf ( "&a = %x\n", &a ); printf ( "&b = %x\n", &b ); return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { int i = 10; int j = 100; char a = 'a'; char b = '0'; double f = 3.14; printf ( "&i = %x\n", &i ); printf ( "&i + 1 = %x\n", &i + 1 ); printf ( "sizeof (int)=%d\n", sizeof ( int ) ); printf ( "&a = %x\n", &a ); printf ( "&a + 1 = %x\n", &a + 1 ); printf ( "sizeof (char)=%d\n", sizeof ( char ) ); printf ( "&f = %x\n", &f ); printf ( "&f + 1 = %x\n", &f + 1 ); printf ( "sizeof (f)=%d\n", sizeof ( f ) ); /* sizeof では、型名だけでなく、変数名もかける */ return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { int i = 10; int *ip; /* 整数へのポインター型変数 */ ip = &i; /* 変数 ip に i へのポインターが入る */ printf ( "*ip = %d\n", *ip ); /* 「*ip」 == 「*(&i)」 == 「i」== 「10」*/ return 0; }
#include <stdio.h> int main(int argc, char *argv[] ) { int a = 100; int b = 200; int c = 300; int *ip; ip = &b; printf ( "&a = %x\n", &a ); printf ( "&b = %x\n", &b ); printf ( "&c = %x\n", &c ); printf ( "ip = %x\n", ip ); printf ( "ip + 1 = %x\n", ip + 1 ); /* アドレス値が sizeof (int) だけ増える */ printf ( "*ip = %d\n", *ip ); /* *ip == *(&b) == b == 200 */ printf ( "*(ip+1) = %d\n", *(ip+1) ); /* ??? */ /* ip + 1 の意味 ポインター値 型情報は ip ( &b )と同じ アドレス値 (&b + 1) 、アドレスとしては sizeof(int) だけ変化 */ printf ( "*(ip-1) = %d\n", *(ip-1) ); /* ??? */ return 0; }
#include <stdio.h> int main(int argc, char *argv[]) { int i = 'A' * 256 + 'B'; printf ( " &i = %d\n", *( &i) ); /* *(&i) == i -> */ printf ( "(char *)&i = %d\n", *((char *)&i) ); /* *((char *)&i) == ? */ /* キャストとは 式の前に 「(型)」とかく事により 式の値を強制的に「型」に変化させてしまう という表現 */ /* (char *)&i ^ 整数型の変数 ^^ 整数型へのポインター値 ^^^^^^ 文字型へのポインター型 ^^^^^^^^^ 文字型へのポインター型へのキャスト ^^^^^^^^^^ 整数型の変数アドレス値をもちながら 型情報は、文字型へのポインター型のポインター値になる */ }
#include <stdio.h> void func001 ( int i ) { /* [1.2] i に 100 が入る */ printf ( "[2] i = %d\n", i ); /* [2] i = 100 */ i = i + 1; /* [2.1] i <- 101 */ printf ( "[3] i = %d\n", i ); /* [3] i = 101 */ } int main ( int argc, char *argv[] ) { int j = 100; printf ( "[1] j=%d\n", j ); /* [1] j=100 */ func001 ( j ); /* [1.1] func001 に 100 が渡される */ printf ( "[4] j=%d\n", j ); /* [4] j=100 */ return 0; }
#include <stdio.h> void func002 ( int *i ) { /* i はポインタ型変数 */ /* [1.2] i には j へのポインタ値が入る */ printf ( "[2] *i = %d\n", *i ); /* [2] *i = *(&j) = j = 100 */ *i = *i + 1; /* [2.1] *i == j <- 101 */ /*^^ 左側に式 ( *i ) がきている : 左辺値 */ printf ( "[3] *i = %d\n", *i ); /* [3] *i = 101 */ } int main ( int argc, char *argv[] ) { int j = 100; printf ( "[1] j=%d\n", j ); /* [1] j=100 */ func002 ( &j ); /* [1.1] j ではなく &j (ポインタ値) */ /* func002 の中で、変数 j の値が書き変わっている */ printf ( "[4] j=%d\n", j ); /* [4] j=100 ではなく j=101 */ return 0; }
#include <stdio.h> void func ( int n, ... ) { /* ,... 引数がさらにあるも.. */ int i; int *ip = &n; /* 一度目 ip -> 1 10 二度目 ip -> 5 100 110 120 130 140 150 */ for ( i = 1; i <= n; i++ ) { /* ip[i] -> *(ip + i) */ /* 一回目 i = 1 〜 1 : ip[i] = ip[1] = 10 */ /* ニ回目 i = 1 〜 5 : io[i] = ip[1] 〜 ip[5] = 100 〜 140 */ printf ( "%d's arg = %d\n", i, ip[i] ); } } int main(int argc, char *argv[] ) { func ( 1, 10 ); /* 1 <- n 10 */ func ( 5, 100, 110, 120, 130, 140, 150 ); /* 5 <- n 100 110 120 130 140 150 */ return 0; }
メモリ セルの集まり セル アドレスと、値 ( 0 〜 255 : 1 byte 分 ) を記憶 変数 メモリの連続した複数のセルからなる 例 : char 型は 1 つのセル 例 : int 型は 4 つのセル 例 : T 型は sizeof(T) 個のセル ポインター 変数名の前に '&' を付けると「ポインター値」が得られる ポインター値 ---+-- アドレス値(番地) +------+-- メモリ | | +-- 型情報 +--- 型のサイズ -+ | | +--- 計算の種類 -+-- 変数 int i; &i <- 整数型へのポインター値 これの型は「整数型へのポインター型」 「int *」 で表現する。 int *ip; ip を「整数型へのポインター値」を保持する変数として宣言 int *ip; --> (*ip) が、int 型 ip = &i; という形で利用 *ip が int 型になる 左辺値 1 = 10; ^ ここには、定数がくるのは駄目 ^ ここにきて欲しいのは、「普通」は、変数名 a = 10; ^ これはただしい 代入文の左側に「式(値を持つもの)」をかきたい a = a + 1; ^ ^ おなじ表現なのに、意味が違う 左は 変数名から左辺値にかわり、そのまま 右は 変数名から左辺値にかわり、さらに右辺値に変る [ポイント] 左辺値を持つ式がかけると嬉しい int i; &i : ポインター値 *(&i) : 変数 i の左辺値になる *(ポインター値) は代入文の左にかいてよい <- 代入文の左にかける「式」がある !! ポインター値というしくみがないと、 !! これができない scanf ( "%d", &i ); /* キーボードから数値を入力し その値を i に代入する */ /* 関数の中で、呼出し元の変数(i) の 値を変更したい -> ポインター値を渡す必要がある -> 変数の前に & が必要 */ まとめ C 言語の変数は、メモリ内の(いくつかの)セル並び char 型は、一個のセル ( sizeof(char)=1 ) T 型は sizeof(T) 個のセルからなる セルなので、アドレスがある 変数名の前に & をつけるとポインター値がえられる アドレス + 型情報 アドレスは、整数を加えると変更できる 型情報は、キャストで変更できる ポインター値に * をつけると、左辺値がでてくる 左辺値から右辺値が作られるので、「変数の値」がとれる 左辺値を利用すると、代入 (変数の値の変更) ができる 「ポインター値」そのものは、右辺値なので、関数の引数に渡せる 関数の呼び元の変数の値を、呼び先の関数の中で変更ができる scanf はこの機能を利用して実現されている === 1: func(x,y) { 2: } 3: main() { 4: func(1,2); 5: return 0; 6: } 振舞 a. main 関数が開始される (3) b. func(1,2) が呼び出される(4) b-1. 2, 1 をスタックに積む b-2. 5 の場所をスタックに積む b-3. 1 の場所に行く c. func(x,y) が呼び出される (1) c-1. x は スタックの上から 2 番目を表している c-2. y は スタックの上から 3 番目を表している [Stack] a +-----+ b-1. 1 +----+ 2 +----+ b-2. (5) <- 5 の場所に戻る +----+ 1 +----+ 2 +----+ c. (5) <- 5 の場所に戻る +----+ 1 <- x +----+ 2 <- y +----+
Download : 20140110-01.c ( SJIS 版 )
/* * DATE-DIR-QQQQ.c * Point2D 型に対応した myprintf を拡張して作る */ #include <stdio.h> #include "s_print.h" #include "s_input.h" /* * */ typedef struct { int x; int y; } Point2D; /* * 複数の引数を書式指定して文字列の中に埋め込む */ void myprintf ( char *msg, ... ) { int i; char *pvalue = (char *)&msg + sizeof( char * ); Point2D pv; for ( i = 0; msg[i] != EOS; i++ ) { if ( msg[i] == '%' ) { /* 文字列の中に '%' があったら特別処理する */ i++; /* 次の文字をみる */ switch ( msg[i] ) { case 'd': /* 10 進数 */ s_print_int ( *((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 'D': /* Point2D 型 */ pv = *((Point2D *)pvalue); /* pv の値を (%d,%d) の形式で出力する */ /* ** この部分を完成させなさい */ /* 次のデータを処理するために pvalue 変更 */ /* ** この部分を完成させなさい */ break; case '%': /* '%' が重なったら.. */ s_print_char ( '%' ); /* '%' を出力 */ break; default: /* その他 : よくわからないので読み飛ばす.. */ break; } } else { /* そうでなけれ .. */ s_print_char ( msg[i] ); /* そのままその文字を出力 */ } } } /* * 色々な数値の出力 */ int main ( void ) { Point2D pv; pv.x = 2; pv.y = -3; /* * データの出力 (Output) */ myprintf ( "整数値(%%d) : %d, 文字(%%c) : '%c', 文字列(%%s) : \"%s\", 浮動小数点数(%%f) : %f, \ 点の座標 (%%D) : %D\n", 123, (int)'a', "xyz" , 1.23, pv ); /* * */ return 0; } /* * */
C:\usr\c\> 20140110-01 整数値(%d) : 123, 文字(%c) : 'a', 文字列(%s) : "xyz", 浮動小数点数(%f) : \ 1.230000, 点の座標 (%D) : (2,-3) C:\usr\c\>