Download : sample-001.c ( SJIS 版 )
/*
* 2014/12/05 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 ac, char *av[] ) {
printf ( "sizeof ( char ) = %d\n", sizeof ( char ) );
printf ( "sizeof ( int ) = %d\n", sizeof ( int ) );
printf ( "sizeof ( double ) = %d\n", sizeof ( double ) );
return 0;
}
#include <stdio.h>
void print_char ( char ch ) {
printf ( "ch = %d\n", ch );
}
int main(int ac, char *av[] ) {
print_char ( 'A' ); /* 'A' という文字を表す ASCII Code を指定 */
/* 'A' は、65 という(ちいさな)整数値になる */
/* 「小さい整数」とは「0 から 255 の 1 byte 表現できる整数」 */
/* あるいは -128 から 127 の範囲 (符号つきの場合) */
print_char ( 65 ); /* 実際に整数を指定しても、同じ */
print_char ( 1000 ); /* 小くなければ .. ? */
print_char ( 1000 % 256 ); /* 小くなければ .. => 余分な部分はきりすてられる */
printf ( "%d\n", 256 * 10 + 20 );
print_char ( 256 * 10 + 20 );
print_char ( 2580 ); /* 2580 = 256 * 10 + 20 */
/* 2580 / 256 = 10 .. 20 */
/* 余りの 20 しかでない */
/*
2580 = 256 * 10 + 20
+-----------+
| 20 | 0 〜 255
+-----------+
| 10 | 0 〜 255
+-----------+
-> 256 * 10 + 20 ( 256 進数法での表現 )
セルが一つ 0 〜 255 = 256 - 1 ( 256 = 2^8 通り )
セルが二つ 0 〜 655xx ( 2^16 通り )
セルが四つ 0 〜 2^32-1 ( 2^32 通り )
-> int の表現できる場合のかず
- 2^(32-1) 〜 2^(32-1) - 1
*/
return 0;
}
#include <stdio.h>
void print_char ( char ch ) {
printf ( "ch = %d\n", ch );
}
int main(int ac, char *av[] ) {
int i;
char ch;
ch = 0;
for ( i = 0; i < 1000; i++ ) { /* i を 0 から 999 まで 1000 回実行 */
printf ( "%d : ", i );
/*
+-----------+
i +-- | 0 | 0 = 0 + 0 * 256^1
| +-----------+ + 0 * 256^2
+-- | 0 | + 0 * 256^3
| +-----------+
+-- | 0 |
| +-----------+
+-- | 0 |
+-----------+
+-----------+
ch -- | 0 | 256 = 0 + 0 * 256^1
+-----------+ + 1 * 256^2
| 1 | + 0 * 256^3
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
*/
/*
127 : ch = 127
128 : ch = -128
セル char int
128 -128 -128
129 -127 -127
-2 -2
255 -1 -1
0 0 0
1 1 1
.. ..
127 127 127
*/
print_char ( ch );
ch = ch + 1; /* ch を 1 ずつ増やす */
/* 最初は 0 : 0, 1 : 1, ... */
}
return 0;
}
#include <stdio.h>
void print_int ( int ch ) {
printf ( "ch = %d\n", ch );
}
int main(int ac, char *av[] ) {
print_int ( 'A' );
print_int ( 65 ); /* 実際に整数を指定しても、同じ */
print_int ( 1000 ); /* 小くなければ .. ? */
print_int ( 2580 ); /* 2580 = 256 * 10 + 20 */
return 0;
}
/*
*/
#include <stdio.h>
typedef struct {
char bytes[sizeof(int)]; /* sizeof int = 4 */
} Int;
void print_int ( Int ch ) {
int i;
for ( i = 0; i < sizeof ( int ); i++ ) {
printf ( "%d\n", ch.bytes[i] );
}
}
#include <stdio.h>
int main(int ac, char *av[] ) {
print_int ( 'A' );
print_int ( 65 ); /* 実際に整数を指定しても、同じ */
/*
+-----------+
65 | 65 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
*/
print_int ( 1000 ); /* 小くなければ .. ? */
print_int ( 2580 ); /* 2580 = 256 * 10 + 20 */
/*
+-----------+
2580 | 20 |
+-----------+
| 10 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
*/
/*
int 型の変数は、sizeof ( int ) のサイズのセルを占有する
*/
return 0;
}
#include <stdio.h>
int main(int ac, char *av[] ) {
int ivar;
char cvar;
/* & は、変数の前につけて、その変数のアドレス(ポインター)値を取る */
printf ( "&ivar = %x\n", &ivar ); /* ivar のアドレス値 */
printf ( "&cvar = %x\n", &cvar ); /* cvar のアドレス値 */
return 0;
}
#include <stdio.h>
void set_char_var ( char *p ) {
/* アドレス値(ポインター値)を利用して、変数の値が変更できる */
*p = 1; /* 引数でしていされた char 型変数へのポインターを使って */
/* その変数の値を書き換える */
}
void set_int_var ( int *p ) {
*p = 1; /* 引数でしていされた int 型変数へのポインターを使って */
/* その変数の値を書き換える */
}
int main(int ac, char *av[] ) {
int ivar = 2;
char cvar = 2;
/* char 型変数の場合 (先週) */
printf ( "前 : cvar = %d\n", cvar );
set_char_var ( &cvar );
printf ( "後 : cvar = %d\n", cvar );
/* int 型変数の場合 (今週) */
printf ( "前 : ivar = %d\n", ivar );
set_int_var ( &ivar );
printf ( "後 : ivar = %d\n", ivar );
return 0;
}
#include <stdio.h>
void print_char_array ( char ch[3] ) {
int i;
for ( i = 0; i < 3; i++ ) {
printf ( "ch[%d] = %d\n", i, ch[i] );
}
}
int main(int ac, char *av[] ) {
char cArray[3] = { 1, 2, 3 };
/*
+-----------+
| 1 | cArray[0]
+-----------+
| 2 | cArray[1]
+-----------+
| 3 | cArray[2]
+-----------+
*/
print_char_array ( cArray );
return 0;
}
#include <stdio.h>
void print_char_array_address ( char ch[3] ) {
int i;
printf ( "関数 : ch = %x\n", ch );
for ( i = 0; i < 3; i++ ) {
printf ( "&ch[%d] = %x\n", i, &ch[i] ); /* アドレスの表示 */
}
/*
配列名は、その配列の先頭の要素のアドレス(ポインター値)をもっている
=>
普通、
関数には、実引数に変数名を指定して、
関数内で、仮引数変数の値を書き換えても、元には影響しない
一方、
関数には、実引数に配列名を指定して、
関数内で、仮引数変数を利用して、配列の要素の値を書き換えると
元の配列の要素の値が書き変わる
*/
}
int main(int ac, char *av[] ) {
char cArray[3] = { 1, 2, 3 };
/*
+-----------+
| 1 | cArray[0]
+-----------+
| 2 | cArray[1]
+-----------+
| 3 | cArray[2]
+-----------+
*/
printf ( "main : ch = %x\n", cArray );
print_char_array_address ( cArray );
return 0;
}
#include <stdio.h>
void print_int_array_address ( int in[3] ) {
int i;
printf ( "関数 : in = %x\n", in );
for ( i = 0; i < 3; i++ ) {
printf ( "&in[%d] = %x\n", i, &in[i] ); /* アドレスの表示 */
}
}
int main(int ac, int *av[] ) {
int iArray[3] = { 1, 2, 3 };
/*
+-----------+
bfd9e7e4 | 1 | iArray[0]
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
bfd9e7e4+4 | 2 | iArray[1]
=bfd9e7e8 +-----------+ &iArray[1] の値は &iArray[0] より sizeof (int) だけ大
| 0 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
| 3 | iArray[2]
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
*/
printf ( "main : in = %x\n", iArray );
print_int_array_address ( iArray );
return 0;
}
#include <stdio.h>
void print_int_array_address ( int in[3] ) {
int i;
printf ( "関数 : in = %x\n", in );
printf ( "in + 1 = %x\n", in + 1 );
printf ( "&in[1] = %x\n", &in[1] );
/*
&in[1] = in + 1 = &in[0] + 1
*/
}
int main(int ac, int *av[] ) {
int iArray[3] = { 1, 2, 3 };
/*
+-----------+
bfd9e7e4 | 1 | iArray[0]
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
bfd9e7e4+4 | 2 | iArray[1]
=bfd9e7e8 +-----------+ &iArray[1] の値は &iArray[0] より sizeof (int) だけ大
| 0 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
| 3 | iArray[2]
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
*/
printf ( "main : in = %x\n", iArray );
print_int_array_address ( iArray );
return 0;
}
/*
* 20141212-01-QQQQ.c
* ポインターを利用して、整数変数の値を正値にする
*/
#include <stdio.h>
/*
* to_positive_int_variable ( int *iVarPtr )
* 指定された整数型の変数の値を正値になるようにする
* int *iVarPtr : 整数型変数へのポインター値
*/
void to_positive_int_variable ( int *iVarPtr ) {
/* int *iVarPtr <=> int iVarPtr[1] */
/* iVarPtr[0] を操作できる iVarPtr は配列と同じだから */
if ( *iVarPtr < 0 ) { /* もし、整数型変数の値が負ならば.. */
/* その値の符号を変更して、元の変数に代入する */
/* *iVarPtr ( = iVarPtr[0] ) の値を変更する必要がある */
*iVarPtr = - *iVarPtr; /* この結果 (当然) *iVarPtr の値が変化 */
/* するが、これは、関数の呼び元の値も変る */
} /* そうでなければ、何もしない.. */
}
/*
*
*/
int main ( int argc, char *argv[] ) {
int pVar = 5; /* 正の値を持つ整数型変数 */
int nVar = -2; /* 負の値を持つ整数型変数 */
int zVar = 0; /* 零の値を持つ整数型変数 */
/* pVar */
printf ( "前 : pVar = %d\n", pVar );
to_positive_int_variable ( &pVar ); /* 引数はポインター値を指定する */
/* 引数には、値を変更させたい変数の「ポインター値」を指定するする必要が
あるので「&pVar」とする必要がある
引数でわたしているのは pVar の「ポインター値」
関数は、その「ポインター値」を利用して pVar を間接的に操作する
*/
printf ( "後 : pVar = %d\n", pVar );
/* nVar */
printf ( "前 : nVar = %d\n", nVar );
to_positive_int_variable ( &nVar );
/* ^この「&」が重要 */
printf ( "後 : nVar = %d\n", nVar );
/* zVar */
printf ( "前 : zVar = %d\n", zVar );
/*
** この部分を完成させなさい
*/
printf ( "後 : zVar = %d\n", zVar );
return 0;
}
/*
*
*/
/*
構造体とポインターの関係
*/
#include <stdio.h>
typedef struct {
int x;
int y;
} Point2D;
/*
* void to_origin ( Point2D *pPtr );
* 引数で指定された Point2D 型の変数のポインター値を利用して
* その変数の値を、原点 ( 0, 0 ) に移す関数
*/
void to_origin ( Point2D *pPtr ) {
(*pPtr).x = 0; /* x 座標を 0 にする */
(*pPtr).y = 0; /* y 座標を 0 にする */
/*
注意 : *pPtr.x は *(pPtr.x) と同じで、これは (*pPtr).x と異る
*/
/*
main 側で &pa を渡すので、ここでは
(*(&pa)).x = 0
(*(&pa)).y = 0
とおなじで、これは
pa.x = 0
pa.y = 0
とおなじ、すなわち、元 main の変数の値を (0,0) した
*/
}
void print_point_2d ( Point2D point ) {
/* Point2D の値がわかればよいので * は不要 */
/* ※ * と & をつかっても良い (may) */
printf ( "(%d, %d)", point.x, point.y );
}
int main(int ac, char *av[] ) {
Point2D pa = { 1, 2 }; /* pa = (1,2) にする */
printf ( "pa = " );
print_point_2d ( pa ); /* ここでは値をわたしている */
/* & はいらない */
printf ( "です\n" );
printf ( "これを原点に移動させると\n" );
to_origin ( &pa ); /* 変数の値を変更するのでポインターを渡す */
/* & を利用 */
printf ( "pa = " );
print_point_2d ( pa ); /* ここでは値をわたしている */
/* & はいらない */
printf ( "となります\n" );
return 0;
}
/*
構造体とポインターの関係(2)
*/
#include <stdio.h>
typedef struct {
int x;
int y;
} Point2D;
/*
* void to_origin ( Point2D *pPtr );
* 引数で指定された Point2D 型の変数のポインター値を利用して
* その変数の値を、原点 ( 0, 0 ) に移す関数
*/
void to_origin ( Point2D *pPtr ) {
pPtr -> x = 0; /* x 座標を 0 にする */
pPtr -> y = 0; /* y 座標を 0 にする */
/*
注意 : 「pPtr -> x」 は 「(*pPtr).x 」と同じ
*/
/*
main 側で &pa を渡すので、ここでは
(*(&pa)).x = 0
(*(&pa)).y = 0
とおなじで、これは
pa.x = 0
pa.y = 0
とおなじ、すなわち、元 main の変数の値を (0,0) した
*/
}
void print_point_2d ( Point2D point ) {
/* Point2D の値がわかればよいので * は不要 */
/* ※ * と & をつかっても良い (may) */
printf ( "(%d, %d)", point.x, point.y );
}
int main(int ac, char *av[] ) {
Point2D pa = { 1, 2 }; /* pa = (1,2) にする */
printf ( "pa = " );
print_point_2d ( pa ); /* ここでは値をわたしている */
/* & はいらない */
printf ( "です\n" );
printf ( "これを原点に移動させると\n" );
to_origin ( &pa ); /* 変数の値を変更するのでポインターを渡す */
/* & を利用 */
printf ( "pa = " );
print_point_2d ( pa ); /* ここでは値をわたしている */
/* & はいらない */
printf ( "となります\n" );
return 0;
}
/*
* 20141212-02-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 型の変数へのポインターの値
*
*
* Y ^
* |
* |
* | P(x,y) <- 元の点
* | |
* ----+-----+-----> X
* | |
* | P'(x,-y) <- X 軸に対称点( y 座標の符号反転する)
* |
* |
*
*/
void move_to_x_axis_symmetry ( Point2D *p2dPtr ) {
/* x 軸に対称なので、y 座標の符号だけを変更 */
p2dPtr -> y = - p2dPtr -> y; /* y 座標の符号を逆転 */
/* その点の y 座標 ( (*p2dPtr).y == p2dPtr -> 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 ); /* 引数は初めからポインター値 */
/* '&' はいらない (すでにポインタ値になっている) */
move_to_y_axis_symmetry ( p2dPtr ); /* 今度は y 座標 */
/* 同様に '&' はいらない (すでにポインタ値になっている) */
}
/*
* print_point2d ( Point2D p2dVar )
* 指定された Point2D 型の値を表示する
* Point2D p2dVar; Point2D 型の値
*/
void print_point2d ( Point2D p2dVar ) {
/* x, y 座標をそれぞれ出力するだけ */
printf ( "(%d, %d)", p2dVar.x, p2dVar.y );
}
/* ポインター版もつくれる */
void print_point2d_by_pointer ( 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 ); */
print_point2d_by_pointer ( &Pa );
printf ( "になります\n" );
printf ( "Pb = " );
print_point2d ( Pb );
printf ( "\nを、原点対称な位置に移動すると.." );
move_to_origin_symmetry ( /*ここ*/ ); /* Pb を利用した何か */
print_point2d ( Pb );
printf ( "になります\n" );
return 0;
}
/*
*
*/
#include <stdio.h>
typedef struct {
char bytes[sizeof(int)];
} Int;
void print_low_byte ( Int v ) { /* 引数は Int 型 sturct { int bytes[4] } */
/*
+-----------+ +-----------+
int | 20 | Int.bytes[0] | 20 |
+-----------+ +-----------+
| 10 | Int.bytes[1] | 10 |
+-----------+ +-----------+
| 0 | Int.bytes[2] | 0 |
+-----------+ +-----------+
| 0 | Int.bytes[3] | 0 |
+-----------+ +-----------+
*/
printf ( "low byte = %d\n", v.bytes[0] );
}
#include <stdio.h>
int main(int ac, char *av[] ) {
print_low_byte ( 10 * 256 + 20 ); /* 引数は int 型 */
/*
+-----------+
int | 20 | = 10 * 256 + 20
+-----------+
| 10 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
*/
return 0;
}
/*
変数 ( メモリのセル集まり.. ) は、それ自身は、型情報をもっていない
それをどようにつかうかは、その内容を「どの型として利用するか」できまる
*/
#include <stdio.h>
#include <stdio.h>
typedef struct {
char bytes[sizeof(int)];
} Int;
void print_low_byte ( Int v ) { /* 引数は Int 型 sturct { int bytes[4] } */
/*
+-----------+ +-----------+
int | 20 | Int.bytes[0] | 20 |
+-----------+ +-----------+
| 10 | Int.bytes[1] | 10 |
+-----------+ +-----------+
| 0 | Int.bytes[2] | 0 |
+-----------+ +-----------+
| 0 | Int.bytes[3] | 0 |
+-----------+ +-----------+
*/
printf ( "low byte = %d\n", v.bytes[0] );
}
int main(int ac, char *av[] ) {
print_low_byte ( 10 * 256 + 20 ); /* 引数は int 型 */
/*
+-----------+
int | 20 | = 10 * 256 + 20
+-----------+
| 10 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
*/
return 0;
}
/*
変数 ( メモリのセル集まり.. ) は、それ自身は、型情報をもっていない
それをどようにつかうかは、その内容を「どの型として利用するか」できまる
*/
#include <stdio.h>
#include <stdio.h>
void print_low_byte_with_pointer ( int *v ) { /* 引数は (int *) 型 */
printf ( "value = %d\n", *v ); /* *(&iVar) == iVar = 10 * 256 + 20 */
}
int main(int ac, char *av[] ) {
int iVar = 10 * 256 + 20;
print_low_byte_with_pointer ( &iVar ); /* 引数は (int*) 型 */
return 0;
}
/*
変数 ( メモリのセル集まり.. ) は、それ自身は、型情報をもっていない
それをどようにつかうかは、その内容を「どの型として利用するか」できまる
*/
#include <stdio.h>
#include <stdio.h>
void print_low_byte_with_pointer ( int *v ) { /* 引数は (int *) 型 */
printf ( "value = %d\n", *(char *)v );
/*
+-----------+
iVar| 20 | ← v は、ココのアドレス + int 型という情報
+-----------+ もし、単に *v とすれば、4 byte 分を利用する
| 10 | ところが、(char *) 型であれば 1 byte 分しか
+-----------+ 利用しない
| 0 |
+-----------+
| 0 |
+-----------+
*/
/*
キャスト
v は int * 型の値 ( int へのポインター型 ) だが、
それをむりやり char * 型 ( char へのポインター型 ) に強制できる
*/
}
int main(int ac, char *av[] ) {
int iVar = 10 * 256 + 20;
/*
+-----------+
iVar| 20 | ← &iVar は、ココのアドレス + int 型という情報
+-----------+
| 10 |
+-----------+
| 0 |
+-----------+
| 0 |
+-----------+
*/
print_low_byte_with_pointer ( &iVar ); /* 引数は (int*) 型 */
return 0;
}
/*
変数 ( メモリのセル集まり.. ) は、それ自身は、型情報をもっていない
それをどようにつかうかは、その内容を「どの型として利用するか」できまる
*/
#include <stdio.h>
/* 階乗の計算 */
int fac ( int n ) {
if ( n <= 0 ) {
return 1;
} else {
return fac ( n - 1 ) * n;
}
}
int main(int ac, char *av[] ) {
printf ( "4! = %d\n", fac ( 4 ) );
/*
4! = 4 * 3 * 2 * 1 = 24
fac ( 4 )
n ← 4; fac( n )
n ← 4; if ( n <= 0 ) {
return 1;
} else {
return fac ( n - 1 ) * n;
}
if ( 4 <= 0 ) {
return 1;
} else {
return fac ( 4 - 1 ) * 4;
}
return fac ( 4 - 1 ) * 4;
return fac ( 3 ) * 4;
4 をかけるというはおいておいて ..
fac(3 )は...
*/
return 0;
}
#include <stdio.h>
/* 階乗の計算 */
int fac ( int n ) {
printf ( "*(%x) = %d\n", &n, n ); /* n のアドレス値を表示してみる */
if ( n <= 0 ) {
return 1;
} else {
return fac ( n - 1 ) * n;
}
}
int main(int ac, char *av[] ) {
printf ( "4! = %d\n", fac ( 4 ) );
/*
4! = 4 * 3 * 2 * 1 = 24
fac ( 4 )
n ← 4; fac( n )
n ← 4; if ( n <= 0 ) {
return 1;
} else {
return fac ( n - 1 ) * n;
}
if ( 4 <= 0 ) {
return 1;
} else {
return fac ( 4 - 1 ) * 4;
}
return fac ( 4 - 1 ) * 4;
return fac ( 3 ) * 4;
4 をかけるというはおいておいて ..
fac(3 )は...
*/
return 0;
}
sizeof ( 型名 )
引数は、「型名」あるいは、「型」を表す表現
その型が、幾つのセルをしめるかを byte 数でしめしてくれる
前回は
char 型変数 <-> メモリモデルの一つセル
& をつける <-> セルのアドレスを取り出す
& をつけたものに * をつける <-> セルそのものをさす
※ & をつけたものは、「値」なので、計算に利用したり、
関数に引数として渡す事や、関数の値として返す事ができる
今回は、int 型に関しても ( int が 4 つ分のセルを占有する以外は、 )
char 型と同じ
同様に、
double 型 / 構造体なども同じように説明できる
==
ポインター値
アドレスと型の二つの情報を持つ値
アドレス : メモリモデルにおける、番地(address)同じもの
型 : それがしめるセルサイズと、それが表す情報の操作方法
-> char, int, double, struct { int x; int y; }, etc.. と同じ
!! ポインター値は、アドレス値 *だけ* をもっているわけではない
!! アドレス値は、整数値として表示できるが、型情報は表示できない
==
関数の引数 (など、変数) は、
スタックにとられている
「スタック」=「棚」
上に、どんどん、物を載せる事ができて、
必要ならば、上にあるものを下して使う使う事ができる
------------------
スタック (最初は空っぽ)
+-------+
| 1 | <- 一つ物を載せた (push)
+-------+
------------------
スタック (内容が 1 つのもの)
+-------+
| 4 | <- 沢山のっている
+-------+
+-------+
| 3 |
+-------+
+-------+
| 2 |
+-------+
+-------+
| 1 |
+-------+
------------------
とりだすときは、最後にいれたものだけがとりだせる
+-------+
| 4 | <- 取り出せるのは、さいごにつんだもの (pop)
+-------+
+-------+
| 3 |
+-------+
+-------+
| 2 |
+-------+
+-------+
| 1 |
+-------+
------------------
fac(int n) {
+----------+
n-> | 4 |
+----------+
------------
fac ( n - 1 ) = fac ( 4 - 1 ) = fac ( 3 )
+----------+
n-> | 3 |
+----------+
+----------+
| 4 |
+----------+
------------
}
main()
{
fac (4) ------------
}
1. 再帰呼出し
メモリモデルで説明ができる
2. 引数が「スタック」とよばれる「メモリ」に保存されている
-> printf の秘密につながる
Download : 20141212-01.c ( SJIS 版 )
/*
* 20141212-01-QQQQ.c
* ポインターを利用して、整数変数の値を正値にする
*/
#include <stdio.h>
/*
* to_positive_int_variable ( int *iVarPtr )
* 指定された整数型の変数の値を正値になるようにする
* int *iVarPtr : 整数型変数へのポインター値
*/
void to_positive_int_variable ( int *iVarPtr ) {
if ( *iVarPtr < 0 ) { /* もし、整数型変数の値が負ならば.. */
/* その値の符号を変更して、元の変数に代入する */
/*
** この部分を完成させなさい
*/
} /* そうでなければ、何もしない.. */
}
/*
*
*/
int main ( int argc, char *argv[] ) {
int pVar = 5; /* 正の値を持つ整数型変数 */
int nVar = -2; /* 負の値を持つ整数型変数 */
int zVar = 0; /* 零の値を持つ整数型変数 */
/* pVar */
printf ( "前 : pVar = %d\n", pVar );
to_positive_int_variable ( &pVar ); /* 引数はポインター値を指定する */
printf ( "後 : pVar = %d\n", pVar );
/* nVar */
printf ( "前 : nVar = %d\n", nVar );
/*
** この部分を完成させなさい
*/
printf ( "後 : nVar = %d\n", nVar );
/* zVar */
printf ( "前 : zVar = %d\n", zVar );
/*
** この部分を完成させなさい
*/
printf ( "後 : zVar = %d\n", zVar );
return 0;
}
/*
*
*/
C:\usr\c\> 20141212-01-QQQQ 前 : pVar = 5 後 : pVar = 5 前 : nVar = -2 後 : nVar = 2 前 : zVar = 0 後 : zVar = 0 C:\usr\c\>
Download : 20141212-02.c ( SJIS 版 )
/*
* 20141212-02-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;
}
/*
*
*/
C:\usr\c\> 20141212-02-QQQQ Pa = (-1, 3) を、x 軸対称な位置に移動すると..(-1, -3)になります Pb = (2, 5) を、原点対称な位置に移動すると..(-2, -5)になります C:\usr\c\>
Download : 20141212-03.c ( SJIS 版 )
/*
* 20141212-03-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\> 20141212-03-QQQQ
整数値(%d) : 123, 文字(%c) : 'a', 文字列(%s) : "xyz", 浮動小数点数(%f) : \
1.230000, 点の座標 (%D) : (2,-3)
C:\usr\c\>