Download : sample-001.c
/*
* 2019/12/20 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;
}
/*
*
*/
$ ./sample-001.exe スタックに 100 を積みます。 スタックに 123 を積みます。 スタックに 999 を積みます。 スタックから取出したデータは 999 です。 スタックから取出したデータは 123 です。 スタックに 876 を積みます。 スタックから取出したデータは 876 です。 スタックから取出したデータは 100 です。 $
Download : sample-002.c
/*
* 2019/12/20 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;
}
/*
*
*/
$ ./sample-002.exe スタックに 100 を積みます。 スタックに 123 を積みます。 スタックに 999 を積みます。 スタックから取出したデータは 999 です。 スタックから取出したデータは 123 です。 スタックに 876 を積みます。 スタックから取出したデータは 876 です。 スタックから取出したデータは 100 です。 $
Download : sample-003.c
/*
* 2019/12/20 sample-003.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;
}
/*
*
*/
$ ./sample-003.exe 整数値(%d) : 1, 文字(%c) : '%', 文字列(%s) : "h`?D?", 浮動小数点数(%f) : 0.000000 $
Download : sample-004.c
/*
* 2019/12/20 sample-004.c
*/
#include <stdio.h>
#include <math.h>
/*
* cf. http://www.asahi-net.or.jp/~uc3k-ymd/Lesson/Section01/section01_06.html
*/
// 10進→2進へ変換して出力
void dec2bin(double x, int bit[])
{
// ビット演算は、整数型または文字型に対して使用しなければならないので、
// 共用体を使って浮動小数点型のデータを文字型(整数型)として参照する
union {
double d; // 8バイト(64ビット)の領域
unsigned char c[8];
} data;
data.d = x; //double型で代入
int i,j, k = 0;
for(i=7; i >= 0; i--) {// 文字型で1バイトごとに取り出す
unsigned char ch = data.c[i];
for(j = 7; j >= 0; j--){ // 1バイト単位で2進数に変換を行う
if( (ch >> j) & 1 ) {
bit[k] = 1;
} else {
bit[k] = 0;
}
// ビットを出力
putchar ( '0' + bit[k] );
k++;
}
putchar ( ' ' ); // 1バイトごとに区切りを入れる
}
putchar ( '\n' );
}
// 仮数部と指数部を2進→10進へ変換して出力する
void bin2dec(int bit[])
{
int BIAS = 1023; // 指数バイアス
// 指数部は0〜2047の値で表されている、この値から
// BIASを引くことで、-1023〜1024の範囲で本当の値が求まる
int exponent=0; // 指数部
double fraction=0.0; // 仮数部の小数点以下
int sign = 1 - 2*bit[0]; //符号ビット0:正、1:負なので
// 0 -> 1 1 -> -1 となる
// 指数部を10進整数に変換
int i;
for (i=11; i>=1; i--) {// 指数部は11ビット
exponent += (int)(bit[i]*pow(2, 11-i));
}
// 仮数部を10進小数に変換
for (i=12; i<=63; i++) {// 仮数部は52ビット
fraction += bit[i]*pow(2, 11-i);
}
printf ( "%f ×2^%d\n", sign * (1.0 + fraction), (exponent - BIAS) );
}
int main(void)
{
int bit[64]; // ビットパターンを格納する
double x;
printf ( "実数値を入力して下さい: " );
scanf ( "%lf", &x );
printf ( "\ndouble型の入力データの内部表現(2進数表示)\n\n"
" [指数部 ][ ---- 仮数部 ----- ]\n" );
dec2bin(x, bit);// 10進→2進へ変換しbit[]に格納する
printf ( "\n入力データ: %f = ", x );
bin2dec(bit);// 仮数部と指数部の2進→10進へ変換
return 0;
}
0.1
$ ./sample-004.exe < sample-004.in 実数値を入力して下さい: 0.100000 double型の入力データの内部表現(2進数表示) [指数部 ][ ---- 仮数部 ----- ] 00111111 10111001 10011001 10011001 10011001 10011001 10011001 10011010 入力データ: 0.100000 = 1.600000 ×2^-4 $
#include <stdio.h>
/*
p-001.c の中身を画面に出力する
*/
int main(int argc, char *argv[]) {
FILE *fp; /* ファイルポインタの宣言 */
/* 「FILE *」型は実際のファイルと結びついて、
そのファイルへの入出力の窓口になる */
int ch; /* 読みこむ文字 */
fp = fopen ( "p-001.c", "r" );
/* ファイル「p-001.c」を"r" (Read:読み込みモード)で「開く」*/
ch = fgetc ( fp ); /* ファイルポインタ fp を経由して「1 文字」読みだす */
while ( ch != EOF ) { /* もし、最後まで読みこんだ後の場合は EOF が返る */
putchar ( ch ); /* その文字を出力し .. */
ch = fgetc ( fp ); /* 次の文字を読みだす */
}
fclose ( fp ); /* ファイルを使い終わったら、それ「閉じる」*/
return 0;
}
#include <stdio.h>
/*
p-002.out にキーボードからの入力を保存する
*/
int main(int argc, char *argv[]) {
FILE *fp; /* ファイルポインタの宣言 */
/* 「FILE *」型は実際のファイルと結びついて、
そのファイルへの入出力の窓口になる */
int ch; /* 読みこむ文字 */
fp = fopen ( "p-002.out", "w" );
/* ファイル「p-002.out」を"w" (Write:書き出しモード)で「開く」*/
ch = getchar(); /* キーボードから「1 文字」読みだす */
while ( ch != EOF ) { /* もし、Ctrl-D が入力された場合は EOF が返る */
/* キーボード入力の終了は、Unix(Linux:Ubuntu) 場合は Ctrl-D */
/* Windows の場合は Ctrl-Z となる */
fputc ( ch, fp ); /* その文字を書き出し .. */
ch = getchar(); /* 次の文字を読みだす */
}
fclose ( fp ); /* ファイルを使い終わったら、それ「閉じる」*/
return 0;
}
#include <stdio.h>
/*
p-002.out にキーボードからの入力を追加する
*/
int main(int argc, char *argv[]) {
FILE *fp; /* ファイルポインタの宣言 */
/* 「FILE *」型は実際のファイルと結びついて、
そのファイルへの入出力の窓口になる */
int ch; /* 読みこむ文字 */
fp = fopen ( "p-002.out", "a" );
/* ファイル「p-002.out」を"a" (Append:追記モード)で「開く」*/
ch = getchar(); /* キーボードから「1 文字」読みだす */
while ( ch != EOF ) { /* もし、Ctrl-D が入力された場合は EOF が返る */
/* キーボード入力の終了は、Unix(Linux:Ubuntu) 場合は Ctrl-D */
/* Windows の場合は Ctrl-Z となる */
fputc ( ch, fp ); /* その文字を書き出し .. */
ch = getchar(); /* 次の文字を読みだす */
}
fclose ( fp ); /* ファイルを使い終わったら、それ「閉じる」*/
return 0;
}
#include <stdio.h>
/*
p-002.out の先頭から、5 byte 目にキーボードからの入力を記録する
*/
int main(int argc, char *argv[]) {
FILE *fp; /* ファイルポインタの宣言 */
/* 「FILE *」型は実際のファイルと結びついて、
そのファイルへの入出力の窓口になる */
int ch; /* 読みこむ文字 */
fp = fopen ( "p-002.out", "r+" );
/* ファイル「p-002.out」を"a+" (書き込みだがシーク可能)で「開く」*/
fseek ( fp, 5L, SEEK_SET );
/* 書き込み位置を、ファイルの先頭(SEEK_SET)から、5 byte 目(5L)の場所に移動 */
ch = getchar(); /* キーボードから「1 文字」読みだす */
while ( ch != EOF ) { /* もし、Ctrl-D が入力された場合は EOF が返る */
/* キーボード入力の終了は、Unix(Linux:Ubuntu) 場合は Ctrl-D */
/* Windows の場合は Ctrl-Z となる */
fputc ( ch, fp ); /* その文字を書き出し .. */
ch = getchar(); /* 次の文字を読みだす */
}
fclose ( fp ); /* ファイルを使い終わったら、それ「閉じる」*/
return 0;
}
#include <stdio.h>
typedef struct {
int x;
int y;
int z;
} Point3D;
void printPoint3D ( Point3D pt ) {
printf ( "(%d, %d, %d)\n", pt.x, pt.y, pt.z );
}
void modifyX ( Point3D *ptp, int newX ) {
(*ptp).x = newX; /* ptp が指す構造体の x を書き換える */
/* 構造体の性質[タグ名を利用して要素が参照できる] */
/* ポインタ値の性質 */
}
void modifyY ( Point3D *ptp, int newY ) {
ptp -> y = newY; /* ptp -> y <=> (*ptp).y は同じ */
}
int main(int argc, char *argv[]) {
Point3D pt;
pt.x = 1;
pt.y = 2;
pt.z = 3;
printPoint3D ( pt );
modifyX ( &pt, 100 ); /* 構造体の x 要素を 100 に変更 */
/* ポインターを渡す事により、呼び出し先で、
呼び出し元の変数の値が変更できる */
printPoint3D ( pt );
modifyY ( &pt, 200 );
printPoint3D ( pt );
return 0;
}
#include <stdio.h>
#define EOS '\0'
int main(int argc, char *argv[]) {
char string[100]; /* サイズ 100 なので、 99 (=100-1[EOS]) までの長さ */
string[0] = 'a';
string[1] = 'b';
string[2] = 'c';
string[3] = EOS; /* string <-> "abc" と同じように扱われる */
/* string[4] ? string[99] の内容は無視される */
string[4] = 'Z';
printf ( "%s\n", string ); /* 文字配列を「文字列」として扱う */
string[3] = '1';
string[5] = EOS;
printf ( "%s\n", string );
return 0;
}
#include <stdio.h>
#include <malloc.h>
/*
文字「リスト」
Linked List の形で実装
"abc"
+-------+ +-------+ +-------+
| *-----> | *-----> |NULL |
+-------+ +-------+ +-------+
| 'a' | | 'b' | | 'c' |
+-------+ +-------+ +-------+
*/
typedef struct cell {
struct cell *next;
char charactor;
} Cell;
/*
Cell <-> struct cell
*/
Cell *make_Cell( Cell *next_, int charactor_ ) {
Cell *cellp = malloc ( sizeof( Cell ) );
if ( cellp != NULL ) {
cellp -> next = next_;
cellp -> charactor = charactor_;
}
return cellp;
}
void print_Cell ( Cell *cellp ) {
if ( cellp != NULL ) {
putchar ( cellp -> charactor );
print_Cell ( cellp -> next );
}
}
void append_charctor ( Cell *cellp, char append ) {
Cell *prev = NULL;
while ( cellp != NULL ) {
prev = cellp;
cellp = cellp -> next;
}
/* prev は、最初に引数で指定された文字リストの最後を指す */
if ( prev != NULL ) {
prev -> next = make_Cell ( NULL, append );
/* 最後の要素に、次の文字を追加する */
}
}
Cell *insert_charctor ( Cell *cellp, char insert ) {
return make_Cell ( cellp, insert );
}
void delete_second_char ( Cell *cellp ) {
Cell *remove = NULL; /* NULL は、「存在するもの」と一致しない事が保証されている */
if ( cellp != NULL ) { /* ポインタ値は、NULL の可能性があるので必ずチェック */
remove = cellp -> next; /* 二文字目 */
cellp -> next = remove -> next; /* 二文字目のセルが切り離される */
free ( remove ); /* 二文字目を保持するセルが不要なので free */
}
}
void all_Cell_free ( Cell *ptr ) {
if ( ptr != NULL ) { /* もし、NULL でなければ */
all_Cell_free ( ptr -> next ); /* 最初に後ろを開放して */
free ( ptr ); /* 後で、自分自身を開放 */
/* 順番は、重要 */
}
}
int main(int argc, char *argv[] ) {
Cell *ptr =
make_Cell (
make_Cell (
make_Cell ( NULL, 'c' ),
'b' ),
'a' );
print_Cell ( ptr );
printf ( "\n" );
append_charctor ( ptr, 'z' );
print_Cell ( ptr );
printf ( "\n" );
ptr = insert_charctor ( ptr, '@' );
print_Cell ( ptr );
printf ( "\n" );
delete_second_char ( ptr );
print_Cell ( ptr );
printf ( "\n" );
all_Cell_free ( ptr ); /* 最後に必ず、alloc したメモリは free する */
return 0;
}
#include <stdio.h>
void sub( int ary[][4] ) { /* 最初の一つの添え字は省略可能だが、それ以外は必要 */
/* why ?
&ary[0] = ary
&ary[1] = ary + 1 -> 番地は、sizeof ( int[4] だけ変化するする必要がある )
後ろの[4] の情報がないと、計算できない
一般に、多次元配列を、関数の引数に渡す場合は、
最初の添え字のサイズだけ、省略可能
*/
}
int main(int argc, char *argv[]) {
int ida[3][4]; /* 二次元配列 */
/* サイズが 4 の(一次元配列)が、3 個並んでいる */
/*
int ida[3][4]; 3 行 4 列の行列
=>
int ida0[4]
int ida1[4]
ind ida2[4]
*/
/*
数学の行列(Matrix) は、二次元配列で表現できる
cf. 今 Deep Learing (AI) で、利用されている
TesorFlow というツールの名前一部である
Tesor : 多次元配列の事
*/
int i;
int j;
int *pi;
for ( i = 0; i < 3; i++ ) {
for ( j = 0; j < 4; j++ ) {
ida[i][j] = i * 10 + j;
}
}
for ( i = 0; i < 3; i++ ) {
for ( j = 0; j < 4; j++ ) {
printf ( "ida[%d][%d] = %d\n", i, j, ida[i][j] );
}
}
for ( i = 0; i < 3; i++ ) {
for ( j = 0; j < 4; j++ ) {
printf ( "&ida[%d][%d] = %p\n", i, j, &ida[i][j] );
}
}
pi = (int *) ida;
for ( i = 0; i < 4 * 3; i++ ) {
printf ( "pi[%d] = %d\n", i, pi[i] );
}
/* 特に.. */
/* ida[n] -> &ida[n][0] */
/* ida[n][0] <-> *(ida[n]+0) */
/* &ida[n][0] <-> &*(ida[n]+0) */
/* &ida[n][0] <-> ida[n] */
sub ( ida ); /* 渡されるのは、メモリモデルの番地番号 */
return 0;
}
前回(2019/12/20)の内容 ファイル I/O C 言語でファイルの内容を扱う「標準ライブラリ」の使い方 「標準ライブラリ」 C 言語の一部ではないが、C 言語が利用できる環境では、 同一の利用法で、同一の効果が得られる事が保証された形で提供される 「C 言語の『移植性』」を担保する役割を担っている cf. 環境(OS)が異なれば、「同じ役割を持つもの」が「同じに使える」保証がない => もし、「異なる環境では異なるプログラム必要」なら、大変 <= しかし、「その違いを吸収するもの」があれば、 同じプログラムを異なる環境で、「そのまま」利用できる可能性がある => プログラムの移植性 <= プログラミング言語が、なんらかのサービスを提供する必要がある C 言語の場合は、「標準ライブラリ」がそれを担保する !!! 特に C 言語の場合は、「ライブラリ」の比重が大きい => C 言語を活用するためには、(じつは..)標準ライブラリの活用法が不可欠 もうしわけないが、ソフトウェア概論では、そのほんの一部しか触れられない => 言語そのものより、多くの内容がある I/O 位 ( printf/scanf/fopen/fclose ) 数学関係 ( sqrt, sin, cos, etc.. ) => 他にもたくさんある => Call by Need (必要になったら調べる..) fopen でファイルを「開き」、ファイルポインタを入手 "r" で読み込み fgetc を使うと、一文字読みこまれるだけでなく、 次の文字を読みだすように、読み出し位置が一つ進む "w" で書き込み fputc を使うと、一文字書き込まれるだけでなく、 次の文字を書き込めるように、次の書き込み先位置が一つ進む # 開いた瞬間、元の内容は、すべて失われる "a" 追記 基本は、"w" と同じだけど、元のファイルの内容は失われず、 最初に書き込む先が、ファイルの最後になる "+" ランダムアクセスも可能 読みこみ場所や書き出し場所を、fseek を利用して、変更可能 fseek を利用する事により、書き出しや読み込み位置が変更 r+ ( read しつつ、書き込みなども可能なる.. ) ファイルポインタと 「f-関数」を利用して「入出力」 Input: fgetc, fscanf, fgets, ... Output: fputc, fprintf, fputs, ... fclose でファイルを「閉じ」る => これを忘れると、いろいろ厄介な事に... # 特に、書き出しの時に、fclose を忘れると、書き込み結果が保証されない可能性がある # !! windows の場合は、運が悪いと、二度と開けないファイルができたりする [落穂ひろい] 構造体のポインターアクセス 構造体へのポインタ値を利用して、その構造体の要素を参照する場合 例: Point3D *ptp;で x 要素を参照する そのポインタ値に*を付けて、かっこでかこってから、タグ名を付ける (*ptp).x とよいが、その省略記法として、-> を利用してもよい ptp -> x (復習) 動的データ型 => alloc (malloc/calloc) を利用して、実行時に、領域を確保して、データを収める 動的データ型は、「不特定多数の要素からなるデータ(を保存する領域)」を扱う型 例 : 文字列 複数の文字からなっている C 言語では、「文字列」を「文字配列」で表現する <= 「配列」そのものは、基本、静的なので、最大サイズをきめて、 その「範囲内」であつかう => 実行時に、「範囲を超えた」サイズは扱えない <= 動的なアプローチを考える 長さが長くなった時点で、それの領域を動的に確保して、追加する => 具体例 : 文字「リスト」を作る Linked List にする事により、原理的(メモリ量が許す限り..)に いくらでも長い文字列が表現できる
課題プログラム内の「/*名前:ここ*/」の部分を書き換え「/*この部分を完成させなさい*/」の部分にプログラムを追加して、プログラムを完成させます。
Download : 20191227-01.c
/*
* 20191227-01-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;
}
/*
*
*/
2.3 9.1 5.9 2.7 3.2
$ ./20191227-01-QQQQ.exe Pa = (-1, 3) を、x 軸対称な位置に移動すると..(-1, -3)になります Pb = (2, 5) を、原点対称な位置に移動すると..(-2, -5)になります $