- 20201204-01-9999.c (20201204-01-9999.c (SJIS))
20201204-01-9999.c
/*
* 20201204-01-QQQQ.c
* 三角形の形をした二次元配列
*
* a[0][0]
* a[1][0] a[1][1]
* a[2][0] a[2][1] a[2][2]
* ..
* a[9][0] a[9][1] a[9][2] .. a[9][9]
*
* a[10][10]
*
* +-------+-------+ ... +-------+
* |a[0][0]|a[0][1]| ... |a[0][9]|
* +-------+-------+ ... +-------+
* |a[1][0]|a[1][1]| ... |a[1][9]|
* +-------+-------+ ... +-------+
* ...
* +-------+-------+ ... +-------+
* |a[9][0]|a[9][1]| ... |a[9][9]|
* +-------+-------+ ... +-------+
*
* メモリ上
*
* +-------+
* |a[0][0]| a[0]
* +-------+
* |a[0][1]|
* +-------+
* | .. |
* +-------+
* |a[0][9]|
* +-------+
* |a[1][0]| a[1]
* +-------+
* |a[1][1]|
* +-------+
* | .. |
* +-------+
* |a[1][9]|
* +-------+
* |a[2][0]| a[2]
* +-------+
* | .. |
* +-------+
* |a[9][9]|
* +-------+
*
* a[i] => ( a[i][k] とすると a[i][k] の場所を参照する )
* a[i][k] <-> *( a[i] + k )
* => a[i] は、実は (& a[i][0])
* i 行目の先頭の要素のアドレス
*
* ひるがえって、次のような三角形の形のものを考える
* a[0][0]
* a[1][0] a[1][1]
* a[2][0] a[2][1] a[2][2]
* ..
* a[9][0] a[9][1] a[9][2] .. a[9][9]
*
* めもりにならべると
*
* +-------+
* |a[0][0]| a[0]
* +-------+
* |a[1][0]| a[1]
* +-------+
* |a[1][1]|
* +-------+
* |a[2][0]| a[2]
* +-------+
* |a[2][1]|
* +-------+
* |a[2][2]|
* +-------+
* |a[3][0]| a[3]
* +-------+
*
* a[i] i
* 0 0
* 1 1
* 3 2
* 6 3
* a[i+1] = a[i] + i + 1 の関係ならば、a[i][j] が三角形の形になっている
*/
#include <stdio.h>
/*
*
*/
#define ARRAY_SIZE 10
#define BASE_SIZE ((ARRAY_SIZE+1)*ARRAY_SIZE/2)
/*
* main
*
* a b
* +-------+ +-------+
* | *---------------> | | a[0] -> b[0]
* +-------+ +-------+
* | *---------------> | | a[1] -> b[1]
* +-------+ +-------+
* | *-----------+ | |
* +-------+ | +-------+
* | *-------+ +---> | | a[2] -> b[3]
* +-------+ | +-------+
* | | |
* | +-------+
* | | |
* | +-------+
* +-------> | | a[3] -> b[6]
* +-------+
* .........
* +-------+
* | | 55 ( 10*(10+1)/2 ) 個の領域
* +-------+
*
* +-------------------+
* a[0] -> |a[0][0] ( b[0] ) |
* +-------------------+
*
* +-------------------+ +-------------------+
* a[1] -> |a[1][0] ( b[1] ) | |a[1][1] ( b[2] ) |
* +-------------------+ +-------------------+
*
* +-------------------+ +-------------------+ +-------------------+
* a[2] -> |a[2][0] ( b[3] ) | |a[2][1] ( b[4] ) | |a[2][2] ( b[5] ) |
* +-------------------+ +-------------------+ +-------------------+
*
*/
int main ( void ) {
int b[BASE_SIZE]; /* 三角形の領域 */
int *a[ARRAY_SIZE]; /* 三角形の配列 */
int i;
int j;
/* 領域の初期化 */
for ( i = 0; i < BASE_SIZE; i++ ) {
b[i] = 1000 + i;
}
/* 三角形の領域の構築 */
a[0] = &b[0]; /* 先頭 ( a[0] = b の方が感じが出ている ) */
for ( i = 1; i < ARRAY_SIZE; i++ ) {
/* 三角形の配列を作る */
a[i] = &b[i*(i+1)/2]; /* ここだけ */
/*
i i*(i+1)/2
1 1
2 3
3 6
*/
}
/* 三角形の領域の参照 */
for ( i = 0; i < ARRAY_SIZE; i++ ) {
printf ( "%d : ", i );
for ( j = 0; j < i + 1; j++ ) {
printf ( "%d ", a[i][j] );
}
printf ( "\n" );
}
return 0;
}
- 20201218-02-9999.c (20201218-02-9999.c (SJIS))
20201218-02-9999.c
/*
* 20201218-02-QQQQ.c
* 二つのファイルを比較して最初に異る場所を表示する
* 二つのファイルをオープンする必要がある
* それぞれ、頭から読み出して、違う所があったら、それを表示する
* ファイルを開くには、ファイル名が必要だが、そのファイル名は、
* コマンドライン引数で指定する
*/
#include <stdio.h>
/*
* main
*/
int main ( int argc, char *argv[] ) {
/* コマンドライン引数を利用して、ファイル名を二つ指定する */
if ( argc != 3 /* 2 + 1 */ ) { /* コマンドライン引数がいくつあるか ? */
printf ( "ファイル名を二つ指定して下さい。\n" );
} else { /* 二つの引数があるので、それをファイル名だと思って、開く */
FILE *fp1; /* 一つ目のファイル */
/* 「代入式」も「式」なので値を持つ */
if ( ( fp1 = fopen ( argv[1], "r" ) ) == NULL ) {
printf ( "ファイル(%s)を開く事ができませんでした。\n", argv[1] );
} else {
FILE *fp2; /* 二つ目のファイル */
if ( ( fp2 = fopen ( argv[2], "r" ) ) == NULL ) {
printf ( "ファイル(%s)を開く事ができませんでした。\n", argv[2] );
} else { /* 二つのファイルが両方、(無事)オープンできた.. */
int position; /* 比較する場所 */
int ch1; /* 一つ目のファイルの今の文字 */
int ch2; /* 二つ目のファイルの今の文字 */
for ( position = 0; (ch1 = fgetc (fp1)) != EOF; position++ ) {
/* 一つ目のファイルから一文字読み込む */
ch2 = fgetc( fp2 ); /* 二文字目を読み込む */
if ( ch1 != ch2 ) { /* 二つの文字を比較 */
break; /* もし、ことなっていたら、中断 *
/* for 構文から抜ける */
}
}
if ( ch1 == EOF ) { /* まだ、ch2 をよみこんでないので .. */
ch2 = fgetc( fp2 ); /* ch2 を読み込む */
/* もし、二つのファイルが同じなら.. ch2 には EOF が入るはず */
/* 逆に、二つ目のファイルが大きい場合は、EOF 以外が入る */
}
if ( ch1 == ch2 ) { /* ともに EOF が入っている */
printf ( "二つのファイル(%s,%s)は同じ内容です。\n", argv[1], argv[2] );
} else if ( ch1 == EOF ) {
printf ( "ファイル(%s) の方がサイズが大きいです。\n", argv[2] );
} else if ( ch2 == EOF ) {
printf ( "ファイル(%s) の方がサイズが大きいです。\n", argv[1] );
} else {
printf ( "%d byte 目で %s は %c, %s は %c という違いがありました。\n", position, argv[1], ch1, argv[2], ch2 );
}
fclose ( fp2 );
}
fclose ( fp1 );
}
}
return 0;
}
- p-001.c (p-001.c (SJIS))
p-001.c
#include <stdio.h>
#include <malloc.h>
/*
最初に入力する数値の個数をいれて、
その個数に対応した配列領域を確保し、
そこにデータを読み込んで、その結果を入力とは逆順に出力する
*/
int main(void) {
int n; /* 入力するデータの個数 */
int *a; /* int へのポインタ変数で、
動的に確保した、配列領域の先頭の要素を指す */
printf ( "入力する整数値の個数を入力してください : " );
scanf ( "%d", &n );
if ( n > 0 ) {
a = malloc ( n * sizeof(int) ); /* 整数型 x 個数 */
if ( a == NULL ) { /* NULL は、alloc がメモリを確保できなかった場合に返す値 */
printf ( "メモリが確保できませんでいた\n" );
} else {
int d; /* 入力する整数値 */
int i; /* 入力回数 / 配列への添え字 */
for ( i = 0; i < n; i++ ) {
printf ( "%d 番目の数値を入力してください : ", i );
scanf ( "%d", &a[i] );
}
for ( i = 0; i < n; i++ ) {
printf ( "%d 番目の数値は %d です\n",
n-i-1,
a[n-i-1]
);
}
free ( a ); /* 動的に確保した領域を解放する */
}
}
return 0;
}
- p-002.c (p-002.c (SJIS))
p-002.c
#include <stdio.h>
/*
テキストファイル ( data.txt ) の中身を、画面の出力する
*/
int main(void) {
FILE *fp; /* ファイルの I/O を行うための
ファイルポインタの宣言 */
/*
「*」がついている事から、「ポインター型」
FILE 型へのポインタ ( FILE へのポインタ型 )
!! FILE 型:
!! ファイルを参照するための情報をもっている
!! ファイル => OS によって異なる
!! !! Windows / Linux では形式が違う
!! !! WSL ( Window のファイルを Linux の形式にみせる仕組み )
!! なかみは、個々に異なるので詳細は、考えなくてよい..
*/
fp = fopen ( "data.txt", "r" );
/* ファイルを開く ( ファイルのオープン ) */
/* ファイルを読み込みモードで開く */
/* data.txt という名前のファイルを参照し、
その情報と結びついた、FILE 型の変数を alloc し、
その変数へのポインタ値を返す */
if ( fp == NULL ) { /* ファイルのオープンに失敗 */
printf ( "ファイルのオープンに失敗しました\n" );
} else { /* ファイルのオープンに成功 */
/* ファイルのオープンに成功したので、ファイルの内容を参照できる */
int ch; /* 読み込みをする変数を用意 */
ch = fgetc ( fp ); /* ファイルポインタ fp に結び付けられている
ファイルから 1 文字入力をする */
/* 入力に失敗した場合は EOF (-1) [整数型] になる */
/* 成功した場合は、文字コード [文字型] */
while ( ch != EOF ) { /* 読み込みに成功した場合は */
putchar ( ch ); /* その読み込んだ文字を出力する */
ch = fgetc ( fp ); /* 次の文字を読み込む */
}
/* ここにくるのは、EOF を読み込んだ (ファイルの最後[の次]を読みだそうとした ) */
fclose ( fp ); /* ファイルのクローズ (ファイルを閉じる) */
}
return 0;
}
- p-003.c (p-003.c (SJIS))
p-003.c
#include <stdio.h>
/*
テキストファイル ( data.txt ) の中身を、
テキストファイル ( output.txt ) にコピーする
*/
int main(void) {
FILE *fp = fopen ( "data.txt", "r" );
if ( fp == NULL ) {
printf ( "ファイルのオープンに失敗しました\n" );
} else {
FILE *fp2 = fopen ( "output.txt", "w" ); /* "w" なので書き出し */
if ( fp2 == NULL ) {
printf ( "ファイルのオープンに失敗しました\n" );
} else {
int ch;
ch = fgetc ( fp );
while ( ch != EOF ) {
fputc ( ch, fp2 ); /* その読み込んだ文字をファイルに書き込む */
ch = fgetc ( fp );
}
fclose ( fp2 );
}
fclose ( fp ); /* ファイルのクローズ (ファイルを閉じる) */
}
return 0;
}
- p-004.c (p-004.c (SJIS))
p-004.c
#include <stdio.h>
int main(int argc, char *argv[]) {
/* main 関数にも、引数がつけらえる (void とかいていたのは、それを無視しているだけ) */
/* !! main 関数は、引数が変化しても問題ない[特別扱い] */
/*
argc/argv を利用して、コマンドライン引数を参照する事ができる
argc -- コマンドライン引数の個数 + 1
argv -- 文字列の配列 ( 文字ポインタの配列 ) になっていて
argv[k] が k ( > 0 ) 番目の引数
argv[0] は、コマンド(ファイル)名自身を指す
*/
int i;
for ( i = 0; i < argc; i++ ) {
printf ( "%d : %s\n", i, argv[i] );
}
return 0;
}
- p-005.c (p-005.c (SJIS))
p-005.c
#include <stdio.h>
int main(void) {
char a[10][10];
int i;
int j;
for ( i = 0; i < 10; i++ ) {
for ( j = 0; j < 10; j++ ) {
printf ( "(%d,%d) : %p\n", i, j, &a[i][j] );
}
}
for ( i = 0; i < 10; i++ ) {
printf ( "a[%d] = %p\n", i, a[i] );
}
return 0;
}
- 1234-a.txt (1234-a.txt (SJIS))
1234-a.txt
2020 ?N?x?u?\?t?g?E?F?A?T?_ B?v(??[????)??p?t?@?C?? (2021/01/15)
[????]
????? CST Portal ???o???邱??
1234-a00.c, .., 1234-a07.c ?????l
??????u<<????>>?v??????????e??u???????鎖
????? 1234 ???????A??????w?Д????u???????鎖
==================================================================
??
??? 1234
???O ?? ?w
a.00
[1234-a00.c ?Q??]
a.01
[1234-a01.c ?Q??]
a.02
[1234-a02.c ?Q??]
a.03
[1234-a03.c ?Q??]
a.04
[1234-a04.c ?Q??]
a.05
[1234-a05.c ?Q??]
a.06
[1234-a06.c ?Q??]
a.07
[1234-a07.c ?Q??]
a.10
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
28218
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
a.12
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
<<????>>
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
a.14
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
<<????>>
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
a.15
[1234-a15.c ?Q??]
a.16
[1234-a16.c ?Q??]
a.17
[1234-a17.c ?Q??]
a.18
[1234-a18.c ?Q??]
a.19
[1234-a19.c ?Q??]
- data.txt (data.txt (SJIS))
data.txt
xyz789
abc999
- memo.txt (memo.txt (SJIS))
memo.txt
2021/01/15 ソフトウェア概論
試験(2021/01/22)の流れ
2021/01/22 のページを開く
ダウロードのページを開く
自分の番号のファイルをダウンロード
内容が微妙に異なるので自分のファイルをダウロードする
# 本日は、20210115-9999.zip を共有する
.zip ファイルは、
c:\usr\c\20210122 にダウンロード
右クリックして、すべて展開
中に question フォルダ
=> q.txt (問題がファイルがある)
それぞれ解く
解答法
ファイルに解答を書き込んで、それを提出 (パターンが二つ)
a) QQQQ-a.txt に直接答えを記入して、複数の解答をまとめて一つで行う問題
b) 一つ一つの問題に対して、一つの C 言語のソースファイルを一答する
!! 全体で、たくさんの問題がある
!! => 解答のファイルもたくさんある
!! => CST Portal IIに提出(アップロードする)
解答法
a) 答えが、プログラムの出力になる問題 ( 例 : Q.10 では 28218 )
これを、QQQQ-a.txt の所定の場所に書き込む
=> 複数の問題の解答を、一つファイル (QQQQ-a.txt)に記入して、
その一つのファイルの提出をもって、(複数の問題の)解答とする
b) Q.00 を例
番号のフォルダに、実行例とテンプレートが入っている
基本、実行例と同じような出力が出るようなプログラムを書く
!! q00.txt と 00.out が一致しない場合
!! => 基本 q00.txt の内容を優先
解答ファイルは、
テンプレートを編集してもよいし、
零から作り直してもよい
!! すで、作成済のファイルを(変更して..)作ってもよい
解答は、CST Portal II にファイルの形で提出する
未提出のものは、採点の対象にならない
できたものだけ、提出するとよい
# 最後にまとめて提出すると CST Portal II が重くなって、
# 提出できない事がおきます。
=> 解答案ができたら、その場で、提出する
==
[前回(2020/12/18)の復習]
動的データ型
<=> C 言語で、これまで学んだデータ型
コンパイル時で、サイズが決まっている ( 静的データ型 )
例:
単純変数宣言 : int i; <= 整数型変数の宣言で、整数 1 つ分を記録
配列宣言 : char c[10]; <= 文字型配列の宣言で、文字 10 つ分を記録
構造体 : struct { int i; double d } s;
<= 構造体の変数宣言で、整数 1 つ分と浮動小数点数 1 つ分を記録
!! 情報を記録するには、メモリを確保する必要がある
!! => 変数宣言を利用すると、その型のメモリを自動的に確保してもらえる
=> 実行時になって初めて、サイズが決まるデータ型
メモリを「動的(実行時)に確保」する仕組みが必要
alloc 関数 ( malloc, calloc : メモリの確保関数 ) と free ( メモリの解放 )
実行時に、必要サイズを指定して、malloc を呼び出し、
必要なサイズの領域を得る
利用が終わったら、わすれずに free を呼び出して、解放する
!! プログラムそのものは free しなくても、うごきます。
!! 大量の領域を alloc して free しないと
!! => メモリ不足になる
前回 : 動的なデータ構造 list を紹介
FILE I/O / ファイル I/O
ファイル操作
ファイル : データを恒常的記憶するための仕組み
<=> メモリの情報 : 電源を切ると失われる
情報を恒常的に記録するには、ファイルに保存する必要がある
大量の情報を入力するときに、キーボードから入力していると大変
=> ファイルに記録して、そこから読み出せると楽
ファイル
情報が永続的に利用可能で、サイズの大きな(文字の..)配列のように利用できる
任意のファイルに対する読み(Read/Input)書き(Write/Output)する機能
ファイルの参照は ( 基本 ) 先頭から、順番に参照する
例 : fgetc では、先頭から 1 文字ずつ読み出す
!! ファイルは、大きな文字配列のように考えられるが、
!! その要素(ファイルに記録されているデータ)への参照は、
!! 逐次的に行うのが普通
!! !! 任意の場所の参照も可能だが、時間がかかる
!! !! cf. List : 先頭は早いが、後ろな遅かった
ファイルの参照 ( I/O : Read/Write ) の場合
FILE ポインター変数の宣言
ファイルのオープン
オープンが成功したかどうかのチェック
# 成功した場合は、ファイルの中身を参照
ファイルのオープンに成功した場合は、最後にクローズする
[コマンドライン引数]
プログラムを実行する時に、そこに、引数 ( コマンドライン引数 ) が追加できる
# ./p-003.exe
# =>
# ./p-003.exe abc 123
# この実行するファイル(名)の後ろに追加された
# 文字列の並び 「abc」と「123」
# # (基本) コマンドライン引数は、空白で区切られる
プログラム中では、
main 関数の引数 ( argc, argv ) を利用して、参照可能
argc は引数の個数 + 1
argv[i] は、i 番目の引数だが、 i = 0 の時は、コマンドファイル名
という形で参照可能
- output.txt (output.txt (SJIS))
output.txt
xyz789
abC999