Download : sample-001.c ( SJIS 版 )
/* * 2014/12/12 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; } /* * */
C:\usr\c>sample-001 スタックに 100 を積みます。 スタックに 123 を積みます。 スタックに 999 を積みます。 スタックから取出したデータは 999 です。 スタックから取出したデータは 123 です。 スタックに 876 を積みます。 スタックから取出したデータは 876 です。 スタックから取出したデータは 100 です。 C:\usr\c>
Download : sample-002.c ( SJIS 版 )
/* * 2014/12/12 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; } /* * */
C:\usr\c>sample-002 スタックに 100 を積みます。 スタックに 123 を積みます。 スタックに 999 を積みます。 スタックから取出したデータは 999 です。 スタックから取出したデータは 123 です。 スタックに 876 を積みます。 スタックから取出したデータは 876 です。 スタックから取出したデータは 100 です。 C:\usr\c>
Download : int_stack.h ( SJIS 版 )
/* * int_stack.h * */ #ifndef _INT_STACK_H_ #define _INT_STACK_H_ /* * Stack Size */ #define INT_STACK_SIZE 100 /* 充分に大きな数と *期待* する */ /* * IntStack 型の定義 */ typedef struct { int stack [ INT_STACK_SIZE ]; /* スタックの本体 */ int sp; /* sp : スタックポインター */ } IntStack; /* IntStack 型の定義 */ /* * IntStack 操作 (プロトタイプ宣言) */ extern void clear_int_stack ( IntStack *isp ); extern void pushd_int_stack ( IntStack *isp, int data ); extern int pop_int_stack ( IntStack *isp ); /* * */ #endif
/* * 2014/12/12 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; /* (1) 現在の場所にデータを保存 */ stack_pointer = stack_pointer + 1; /* (2) スタックポインターは「次」を指す */ /* データは「現在の場所」に保存され、 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; } /* * */
#include <stdio.h> void sub2(void) { int i = 1234; /* 変数が利用したい / スタックの上の部分を利用 */ /* <sub2> 一回目 * +------+ * bfa7f45c | | <- i のためにつかっている (その先) * +------+ * bfa7f45b | | <- ここまでは main が使っている * +------+ * | ... | <- * +------+ * bfa7f45? | | <- sp * +------+ * | | * +------+ * | ... | */ /* <sub2> ニ回目 * +------+ * bfa7f42c | | <- sub2 がつかっている * +------+ * | ... | * +------+ * bfa7f45c | | <- sub1 がつかっている * +------+ * bfa7f45d | | <- ここまでは main が使っている * +------+ * | ... | <- * +------+ * bfa7f45? | | <- sp * +------+ * | | * +------+ * | ... | */ printf ( "sub2: %x\n", &i ); /* 変数 i のアドレス */ } void sub1(void) { int i; /* <sub1> 一回目 * +------+ * bfa7f45c | | <- i のためにつかっている (その先) * +------+ * bfa7f45b | | <- ここまでは main が使っている * +------+ * | ... | <- * +------+ * bfa7f45? | | <- sp * +------+ * | | * +------+ * | ... | */ printf ( "sub1: %x\n", &i ); /* 変数 i のアドレス */ printf ( "sub1: i=%d\n", i ); /* 変数 i に値をいれていないのに ?? */ sub2(); } int main(int ac, char *av[]){ /* <main> * | ... | * +------+ * bfa7f45? | | <- sp * +------+ * | | * +------+ * | ... | */ sub1(); /* sub2 が sub1 から間接的によびだされる */ sub2(); /* sub2 を直接呼び出す */ return 0; }
#include <stdio.h> void sub2(void) { int i = 1234; printf ( "sub2: %x\n", &i ); /* 変数 i のアドレス */ } void sub1(void) { int i; printf ( "sub1: %x\n", &i ); /* 変数 i のアドレス */ printf ( "sub1: i=%d\n", i ); /* 変数 i に値をいれていないのに ?? */ sub2(); } int main(int ac, char *av[]){ sub2(); /* sub2 を直接呼び出す */ sub1(); /* sub2 が sub1 から間接的によびだされる */ return 0; } /* 一回目 sub2 が bfa7f45c の場所を i として利用し 1234 を代入した 一回目 sub1 が bfa7f45c の場所を i として利用し、 1234 の値を取出した sub2 は、 bfa7f42c の場所を i として利用するので、bfa7f45c の場所は使用しない
/* * 関数の変数がスタックに作れる ( p-002,003 ) * では、引数変数は ? */ #include <stdio.h> void sub ( int j ) { int k; printf ( "&j = %x\n", &j ); printf ( "&k = %x\n", &k ); } int main ( int ac, char *av[] ) { int i; printf ( "&i = %x\n", &i ); sub ( 123 ); /* 関数に引数を渡す */ return 0; } /* C 言語の Stack +-----------+ | | <- sub の 変数 k +-----------+ | ... | +-----------+ | | <- sub の 引数 j +-----------+ | ... | +-----------+ | | <- main の 変数 i +-----------+ 引数変数も、スタックの上に作られている */
#include <stdio.h> void sub ( int n, int top ) { int i; for ( i = 0; i < n; i++ ) { printf ( "%d => %d\n", i, (&top)[i] ); /* | | <- SP +-------+ n | | +-------+ top | | +-------+ | | n=1, sub ( 1, 123 ) | | <- SP +-------+ n | 1 | +-------+ top | 123 | +-------+ | | n=2, sub ( 2, 123, 456 ) | | <- SP +-------+ n | 2 | +-------+ top | 123 | +-------+ | 456 | +-------+ | | n=3, sub ( 3, 123, 456, 789 ) | | <- SP +-------+ n | 3 | +-------+ top | 123 | <- (&top)[0] -> *(&top + 0) -> *(&top) -> top --> 123 +-------+ (t2)| 456 | <- (&top)[1] -> *(&top + 1) -> *(&top + 1) -> t2 --> 456 +-------+ (t3)| 789 | +-------+ | | */ } }
/* * 関数の変数 * では、引数変数順序と場所の関係は ? */ #include <stdio.h> int main ( int ac, char *av[] ) { /* 最初の引数は、実際にデータとして渡したデータの個数を表現 */ /* 二つ目以後は、実際に渡したいデータの内容を並べる */ sub ( 1, 123 ); /* 関数に引数を一つ渡す */ /* | | <- Stack Pointer +-------+ | 1 | <- 最初の引数 +-------+ | 123 | <- 二つ目の引数 +-------+ */ sub ( 2, 123, 456 ); /* 関数に引数を二つ渡す */ /* | | <- Stack Pointer +-------+ | 2 | <- 最初の引数 +-------+ | 123 | <- 二つ目の引数 +-------+ | 456 | <- 二つ目の引数 +-------+ */ sub ( 3, 123, 456, 789 ); /* 関数に引数を三つ渡す */ /* | | <- Stack Pointer +-------+ | 2 | <- 最初の引数 +-------+ | 123 | <- 二つ目の引数 +-------+ | 456 | <- 二つ目の引数 +-------+ | 789 | <- 三つ目の引数 +-------+ */ return 0; } /* C 言語の Stack +-----------+ | | <- sub の 変数 k +-----------+ | ... | +-----------+ | | <- sub の 引数 j +-----------+ | ... | +-----------+ | | <- main の 変数 i +-----------+ 引数変数も、スタックの上に作られている */
#include <stdio.h> /* myprintf (version 1) 最初の文字列しか表示しない */ void myprintf ( char *fmt, ... ) { /* 引数の所の 「...」は、この部分は、以後、可変長 引数は、一つ以上 (すくなくても一つは fmt という変数がある)で、 幾つあるか(また、その型が何であるか)はわからない場合に使う */ printf ( "%s", fmt ); } int main(int ac, char *av[]) { myprintf ( "abc\n" ); }
#include <stdio.h> /* myprintf (version 2) 最初の文字列しか表示しない けど、一文字ずつ出力する ( printf のかわりに putchar() ) */ #define EOS '\0' /* End Of String の宣言 */ void myprintf ( char *fmt, ... ) { int i; for ( i = 0; fmt[i] != EOS; i++ ) { putchar ( fmt[i] ); /* 一文字出力だけを利用 */ /* 一応、文字列の中の文字をみている */ /* printf をつかっていない */ } /* 文字列は、char 型の配列と同じ構造を持つ (char 型の配列の要素に、それぞれ ascii code がはいっていて 最後に EOS がはいっているだけ) */ } int main(int ac, char *av[]) { myprintf ( "abc\n" ); /* \n の処理はコンパイラがやる */ myprintf ( "「%」とかいても OK\n" ); /* \n の処理はコンパイラがやる */ }
#include <stdio.h> /* myprintf (version 3) fmt の中に '%' がでてきたら、 その後の整数値におきかえる % は、一個でよい 引数は整数しか、考えない */ #define EOS '\0' /* End Of String の宣言 */ void myprintf ( char *fmt, ... ) { int i; /* +-------+ fmt | | <- &fmt : 型は「char *」 +-------+ fmt+1 | | <- 数値 ? +-------+ */ for ( i = 0; fmt[i] != EOS; i++ ) { /* 一文字ずつ */ if ( fmt[i] != '%' ) { /* '%' だけ特別あつかい */ putchar ( fmt[i] ); /* いつもと同じ */ } else { printf ( "%d", *((int *)(&fmt + 1)) ); /* &fmt --> 最初の引数 ( char * 型 ) の変数のアドレスを取る &fmt + 1 --> 二つ目の引数 ( char * 型 ) の変数アドレスを取る (int *)(&fmt + 1) --> 二つ目の引数 ( int 型 ) の変数アドレスを取る *((int *)(&fmt + 1)) --> 二つ目の引数 ( int 型 ) の値 ( int 型 )を得る */ } } } int main(int ac, char *av[]) { myprintf ( "abc\n" ); /* \n の処理はコンパイラがやる */ myprintf ( "「%」の所には整数値\n", 123 ); myprintf ( "「%」「%」「%」「%」の所には整数値\n", 123, 456, 789 ); return 0; }
#include <stdio.h> #define EOS '\0' /* End Of String の宣言 */ void myprintf ( char *fmt, ... ) { int i; for ( i = 0; fmt[i] != EOS; i++ ) { /* 一文字ずつ */ if ( fmt[i] != '%' ) { /* '%' だけ特別あつかい */ putchar ( fmt[i] ); /* いつもと同じ */ } else { printf ( "%d", *((int *)(&fmt + 1)) ); } } } int main(int ac, char *av[]) { myprintf ( "abc\n" ); /* \n の処理はコンパイラがやる */ myprintf ( "「%」の所には整数値\n", 123 ); return 0; }
#include <stdio.h> /* myprintf (version 3) fmt の中に '%' がでてきたら、 その後の整数値におきかえる % は、一個でよい 引数は整数しか、考えない 一つ目の '%' は、二つ目の引数 二つ目の '%' は、三つ目の引数 ... という形で、出力したい <<ポイント>> 幾つ '%' がでたかを憶えおく必要がある */ #define EOS '\0' /* End Of String の宣言 */ void myprintf ( char *fmt, ... ) { int i; int *argp; /* 次の引数のアドレスを持つ変数 */ /* 「ポインター変数」:ポインター値を持つ変数 */ /* 実は fmt は、char 型へのポインター変数なので */ argp = (int *)(&fmt + 1); /* 最初の引数のポインター値とっておく */ /* +-------+ fmt | | <- &fmt : 「char *」型の変数へのポインター +-------+ +------------------------------------+ | | <- argp | 値は fmt の次の変数のポインター値 | +-------+ +------------------------------------+ | | <- argp + 1 (アドレスとしては sizeof(int) だけずれる) +-------+ */ for ( i = 0; fmt[i] != EOS; i++ ) { /* 一文字ずつ */ if ( fmt[i] != '%' ) { /* '%' だけ特別あつかい */ putchar ( fmt[i] ); /* いつもと同じ */ } else { printf ( "%d", *argp ); /* argp (int * 型)に * をつけると int */ argp = argp + 1; /* 今の *argp は使ったので */ } /* 次の 引数を指すように +1 する */ } } int main(int ac, char *av[]) { myprintf ( "abc\n" ); /* \n の処理はコンパイラがやる */ myprintf ( "「%」の所には整数値\n", 123 ); myprintf ( "「%」「%」「%」「%」の所には整数値\n", 123, 456, 789, 999 ); return 0; }
#include <stdio.h> /* myprintf (version ?) 引数は整数以外にも OK %d => 整数値 %f => 浮動小数点数 */ #define EOS '\0' /* End Of String の宣言 */ void myprintf ( char *fmt, ... ) { int i; int *argp; /* 次の引数のアドレスを持つ変数 */ /* 「ポインター変数」:ポインター値を持つ変数 */ /* 実は fmt は、char 型へのポインター変数なので */ argp = (int *)(&fmt + 1); /* 最初の引数のポインター値とっておく */ for ( i = 0; fmt[i] != EOS; i++ ) { /* 一文字ずつ */ if ( fmt[i] != '%' ) { /* '%' だけ特別あつかい */ putchar ( fmt[i] ); /* いつもと同じ */ } else { i++; /* '%' の次の文字みる */ if ( fmt[i] == 'd' ) { printf ( "%d", *argp ); argp = argp + 1; } else if ( fmt[i] == 'f' ) { /* 浮動小数点数の表示 */ } } } } int main(int ac, char *av[]) { myprintf ( "abc\n" ); /* \n の処理はコンパイラがやる */ myprintf ( "「%d」の所には整数値\n", 123 ); myprintf ( "「%d」「%d」「%f」「%d」の所には整数値\n", 123, 456, 789, 999 ); return 0; }
#include <stdio.h> /* myprintf (version ?) 引数は整数以外にも OK %d => 整数値 %f => 浮動小数点数 */ #define EOS '\0' /* End Of String の宣言 */ void myprintf ( char *fmt, ... ) { int i; int *argp; /* 次の引数のアドレスを持つ変数 */ /* 「ポインター変数」:ポインター値を持つ変数 */ /* 実は fmt は、char 型へのポインター変数なので */ argp = (int *)(&fmt + 1); /* 最初の引数のポインター値とっておく */ for ( i = 0; fmt[i] != EOS; i++ ) { /* 一文字ずつ */ if ( fmt[i] != '%' ) { /* '%' だけ特別あつかい */ putchar ( fmt[i] ); /* いつもと同じ */ } else { i++; /* '%' の次の文字みる */ if ( fmt[i] == 'd' ) { printf ( "%d", *argp ); argp = argp + 1; } else if ( fmt[i] == 'f' ) { printf ( "%f", *(double *)argp ); argp = argp + 2; /* <- int -> sizeof int == 4 +-------+ | | +-------+ +-------+ | | sizeof double == 8 -> int 二つ分 + + | | +-------+ myprintf ( "..", 123, 456, 789.654, 999 ) +-------+ | ".." | +-------+ | 123 | +-------+ | 456 | +-------+ | 789. | <- argp | 654 | <------- argp + 1 +-------+ | 999 | <------- argp + 2 +-------+ } } } } int main(int ac, char *av[]) { myprintf ( "abc\n" ); /* \n の処理はコンパイラがやる */ myprintf ( "「%d」の所には整数値\n", 123 ); myprintf ( "「%d」「%d」「%f」「%d」の所には整数値\n", 123, 456, 789.654, 999 ); return 0; }
#include <stdio.h> /* myprintf (version ?) 引数は整数以外にも OK %d => 整数値 %f => 浮動小数点数 char * ポインターを使う */ #define EOS '\0' /* End Of String の宣言 */ void myprintf ( char *fmt, ... ) { int i; char *argp; /* Why : sizeof int はコンピュータによって異る */ /* -> sizeof double が sizeof int に二倍である保証がない */ /* sizeof char == 1 は保証されている */ argp = (char *)(&fmt + 1); /* 最初の引数のポインター値とっておく */ for ( i = 0; fmt[i] != EOS; i++ ) { /* 一文字ずつ */ if ( fmt[i] != '%' ) { /* '%' だけ特別あつかい */ putchar ( fmt[i] ); /* いつもと同じ */ } else { i++; /* '%' の次の文字みる */ if ( fmt[i] == 'd' ) { /* int 型 */ printf ( "%d", *(int *)argp ); argp = argp + sizeof(int); /* (char *)((int *)argp + 1) */ } else if ( fmt[i] == 'f' ) { /* double 型 */ printf ( "%f", *(double *)argp ); argp = argp + sizeof(double); } else if ( fmt[i] == 's' ) { /* 文字列 ( char * ) */ printf ( "%s", *(char **)argp ); argp = argp + sizeof(char *); } } } } int main(int ac, char *av[]) { myprintf ( "abc\n" ); myprintf ( "int 型 : %d, double : %f, 文字列型 : %s\n", 123, 456.789, "abc" ); return 0; }
#include <stdio.h> /* myprintf (version ?) 自分で作成した、Point2D 型も %D で出力できるようにしよう */ #define EOS '\0' /* End Of String の宣言 */ typedef struct { int x; int y; } Point2D; /* Point2D 型をつくった */ void myprintf ( char *fmt, ... ) { int i; char *argp; /* Why : sizeof int はコンピュータによって異る */ /* -> sizeof double が sizeof int に二倍である保証がない */ /* sizeof char == 1 は保証されている */ argp = (char *)(&fmt + 1); /* 最初の引数のポインター値とっておく */ for ( i = 0; fmt[i] != EOS; i++ ) { /* 一文字ずつ */ if ( fmt[i] != '%' ) { /* '%' だけ特別あつかい */ putchar ( fmt[i] ); /* いつもと同じ */ } else { i++; /* '%' の次の文字みる */ if ( fmt[i] == 'd' ) { /* int 型 */ printf ( "%d", *(int *)argp ); argp = argp + sizeof(int); /* (char *)((int *)argp + 1) */ } else if ( fmt[i] == 'f' ) { /* double 型 */ printf ( "%f", *(double *)argp ); argp = argp + sizeof(double); } else if ( fmt[i] == 's' ) { /* 文字列 ( char * ) */ printf ( "%s", *(char **)argp ); argp = argp + sizeof(char *); } else if ( fmt[i] == 'D' ) { /* Point2D */ printf ( "(%d,%d)", ((Point2D *)argp) -> x, ((Point2D *)argp) -> y ); argp = argp + sizeof(Point2D); } } } } int main(int ac, char *av[]) { Point2D Pa = { 10, 15 }; myprintf ( "abc\n" ); myprintf ( "int 型 : %d, double : %f, 文字列型 : %s\n", 123, 456.789, "abc" ); myprintf ( "Point2D : %D\n", Pa ); return 0; }
/* * 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) の形式で出力する */ printf ( "(%d,%d)", pv.x, pv.y ); /* s_print_char ( '(' ); s_print_int ( pv.x ); s_print_char ( ',' ); s_print_int ( pv.y ); s_print_char ( ')' ); */ /* 次のデータを処理するために pvalue 変更 */ pvalue += sizeof ( /* 何か */ ); 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; } /* * */
スタックとは 複数のデータを、順序付きで記録でき、その出し入れが可能なデータの容れ物 # 入れる順序が変ると、出る順序が変る 新しく追加する物は上に積まれる / 取り出す場合も一番上から +-----------+ | データ | <= 一番上が、最新 +-----------+ +-----------+ | データ | +-----------+ +-----------+ | データ | +-----------+ --------+-----------+----- 棚 新しい物は上に積んでゆく -> どんどん、積み重ねる事により、沢山保持できる (利点:少ないスペースで大量のデータが保持できる) 棚から取り出せるのは一番上の物だけ (欠点:最新のものしか取り出せない) <<比較>> ランダムアクセスメモリ どこでも参照できる(利点) 広い(アドレス)空間が必要(欠点) 特定の場合は便利で 記憶領域の効率的(無駄がなくて、かつ簡単にできる)な記憶方式 スタック操作 push data ; data をスタック(の一番上)に載せる pop ; スタックのトップのデータ取出し、スタックからそのデータを取り除く 「スタック」は、「pushd/popができるもの」として認識される => 「それが何からできているか/どうやって作られているか ?」には興味がない 「それがどのように扱えるか ?」にしか興味がない (オブジェクト指向) -> 抽象データ型 スタックでは、 最初に入れた物 ( First In ) が、最後に出て来る ( Last Out ) ので FILO と呼ぶ # cf. FIFO ( First In First Out ) は Queue (行列) [結論] スタックは、便利で、良く出てくる考え == C 言語でも、スタックが利用されている 関数呼び出しの時に、変数を管理するためにスタックが利用されている p-002.exe の実行結果 sub2: bfc1f32c <- 一回目の sub2 の i のアドレス sub1: bfc1f32c <- ニ回目の sub1 の i のアドレス (一回目の sub2 と同じ) sub2: bfc1f2fc <- ニ回目の sub2 の i のアドレス (一回目と違う) [結論] C の(auto)変数は、スタック上に作られる == 多分岐構文 switch 文 状況 一つの変数 ( int 型 [か、char 型..] ) の値によって、 多数の選択肢の一つを実現したい場合を考える 事例 : トランプの位を出力 トランプ (変数 trump) は 1 から 13 の数でカードの位を表すが、 それを表示する場合に.. 1 -> A とする 2 〜 10 -> そのまま 2 〜 10 11 -> J 12 -> Q 13 -> K 解答 A : if 文 ( else if ) を利用する void print_trump ( int trump ) { if ( trump == 1 ) { printf ( "A" ); } else if ( trump == 11 ) { printf ( "J" ); } else if ( trump == 12 ) { printf ( "Q" ); } else if ( trump == 13 ) { printf ( "K" ); } else if ( 2 <= tump && tump <= 10 ) { printf ( "%d", trump ); } else { printf ( "What ???\n" ); } } 解答 B : switch 文を利用する 構文 switch ( 式 ) { case 定数1: /* 式の値 == 定数 1 の時 */ .. case 定数2: /* 式の値 == 定数 2 の時 */ .. default: /* 式の値 == 定数 k の何れともちがう場合 */ } !! break; があると、そこで、switch 文を終了する !! break; がないと、次の case にいってしまう void print_trump ( int trump ) { switch ( trump ) { case 1: /* if ( trump == 1 ) の所 */ printf ( "A" ); break; case 11: printf ( "J" ); break; case 12: printf ( "Q" ); break; case 13: printf ( "K" ); break; default: if ( 2 <= tump && tump <= 10 ) { printf ( "%d", trump ); } else { printf ( "What ???\n" ); } break; } /* さらに .. */ void print_trump ( int trump ) { switch ( trump ) { case 1: /* if ( trump == 1 ) の所 */ printf ( "A" ); break; case 11: printf ( "J" ); break; case 12: printf ( "Q" ); break; case 13: printf ( "K" ); break; case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: printf ( "%d", trump ); break; default: printf ( "What ???\n" ); break; }
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\>