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\>