こんにちは。 #3、#4です。
まず始めに、#3の内容について訂正致します。
#5さんがご提示されたソースにより、「標準入力」の再オープンが可能なことが
解りました。(※#5さんに感謝致します。)
ですので、#3で書いた、キーボードから直接入力する方法
以外にも、このような、
『キーボードから入力する方法はある』
ということで訂正させて戴きます。 すみませんでした。
=========================
ここから、本題です。
※#5さんへの「補足」の件です。
> 提示していただいたプログラムですが、内容を表示する関数であるprint_queue_mtrxに
> in functinとmultiple definitionエラーが出ます。
> 分割されている関数、
> が重複するためだとは思うんですが、単純にそこだけ入れ替えても仕方がないですし・・・。
ソースの構成を、
1)main関数があるメインソース(print_queue_mtrx関数を参照している側)
2)print_queue_mtrx関数の実体を書いているソース
のように「別々のソース」にしている状況で、
#5さんが提示されたソースをそのまま使用してビルドを行うと、リンク時に、
上記のようなエラー(関数の二重定義)が発生してしまいます。
ですので、対処としては、ソース構成を、
1)メインソースから、print_queue_mtrx関数の実体部分のコードを削除し、
print_queue_mtrx関数の実体は別ソースで記述する。
※print_queue_mtrx関数の実体部分を1つにする。
⇒ソースは、複数ソース構成
または、
2)メインソース側に、全部のソースコードをまとめて、1つのソースにして、
他のソースは使用しない。
⇒ソースは、1ソース構成
のようにしないといけないと思います。
> このプログラムを単体でコンパイルしても
> freopen("CON","r",stdin); /* 標準入力をコンソールに切り替え */
> の部分がどうも機能しているようには思えないのですが・・・。
> 僕から見ればなんで機能してないのかわかりません・・・。
もしかしたら、ご使用の開発環境は、UNIX系(Linux系及び、Windows下のCygwin環境
も含む)をお使いでしょうか?
だとした場合、#5さんのご提示されたソースの下記部分、
freopen("CON","r",stdin); /* 標準入力をコンソールに切り替え */
※こちらは、Windows系(MS-DOS系も含む)の場合。
は、
freopen( "/dev/tty", "r", stdin ); /* 標準入力をコンソールに切り替え */
※こちらは、UNIX系(Linux系、Windows下のCygwin環境も含む)の場合。
注)"/dev/tty"の部分は、環境に合わせて変えないといけないかもしれません。
のように、
コンソール機器に対応する「デバイスファイル名」を変えないといけないと思います。
以上の内容を考慮して、下記サンプルを掲載致します。
■下記サンプルについての補足
1)ソース構成は、2ソース構成にしてあります。
<ソース構成>
1: mainque2.c メインソース
2: printque2.c print_queue_mtrx関数の実体ソース
2)Queue操作用の「コマンド」を下記のように追加してあります。
<Queue操作用のコマンド一覧>
0: Exit. ← プログラム終了
1: De Queue. ← キューから1データ(1文字)削除
2: Display Queue. ← キューの内容表示
3: Initialized Queue. ← キューの初期化
9: Display this HELP. ← キュー操作コマンドの一覧表示(ヘルプ)
3)キューの構造は、リングバッファの構造に変更してあります。
rear、topの値は、上限値(MAX-1)を超えた場合は、0 に戻すようにしています。
これに伴い、キュー操作用の関数に対して、多少変更を加えてあります。
4)検証のため、#defineで定義しているキューサイズを下記のように変更しています。
#define MAX 10 /* キューのサイズ(※デバッグ用)*/
5)文字入力を行う下記のループ部分は、入力区分(リダイレクト入力、コンソール入力)
で共通に使えるように、1つにしてあります。
/* 1文字ずつ読み込む */
while ( ( ich = getc( stdin ) ) != EOF ) {
:
}
6)開発環境による、コンソールデバイスの違いに対応するために、下記のように、
#define定義の設定値により、切替えられるようにしています。
==============================================
#define OS_TYPE 1 /* OS(処理系)のタイプ */
/* =0:Windows系、=1:UNIX/Linux/Cygwin系 */
:
:
#if OS_TYPE==0 /* Windows系の場合 */
freopen( "CON", "r", stdin );
#else /* UNIX/Linux/Cygwin系の場合 */
freopen( "/dev/tty", "r", stdin );
#endif
==============================================
※今回は、2パターンのみですが、これ以外のパターン(環境)の場合は、
環境に合わせて、上記部分を変更して下さい。
■サンプルソース
注)インデント等のため全角スペースを入れています。
・ご使用の際は半角スペースorタブに置換して下さい。
◎メインソース
=========================
/*
* mainque2.c:リングバッファタイプのキュー操作(メインソース)
*/
#include <stdio.h>
#include <stdlib.h>
#define OS_TYPE 1 /* OS(処理系)のタイプ */
/* =0:Windows系、=1:UNIX/Linux/Cygwin系 */
//#define MAX 100 /* キューのサイズ */
#define MAX 10 /* キューのサイズ(※デバッグ用)*/
/* 注)キューに登録できるデータの最大登録数は(MAX-1)までとなる。 */
/* ※リングバッファ構造で、登録データ数の管理をtopとrearのみで行い、*/
/* かつ、top==rearの時を「登録データなし」と意味付けているため、 */
/* もしも登録数上限をMAXとした場合、キュー初期化時のtop=rearの場合*/
/* を除き2回目以降のtop==rearの状態が登録数上限となるのを防ぐ為。*/
/* 関数プロトタイプ(外部ソースの関数) */
/* ※top == rear ならばキューは空キューの値は、*/
/* top/rearの値が増える方向に積まれていく。 */
void print_queue_mtrx( char* q, int top, int rear, int qmax );
/* 関数プロトタイプ(本ソース内)*/
int enqtoQueue( char *ch );
int deqfromQueue( char *ch );
char peekofQueue();
void initializeQueue();
void print_help();
/* キューデータ */
char queue[ MAX ];
int top = 0;
int rear = 0;
/* キューへのデータ登録 */
int enqtoQueue( char *ch )
{
int num;
/* キュー内のデータ登録数を計算 */
if( rear >= top )
num = rear - top;
else
num = MAX - (top - rear);
/* 登録数が上限の場合は戻る(※終了はしない)*/
if ( num >= (MAX - 1) ) {
fprintf( stderr, "Queue Overflow!!\n" );
/* exit( 1 ); */
return -1;
}
/* キューへのデータ登録+rearポインタ更新 */
queue[ rear ] = *ch;
rear = (rear + 1) % MAX;
return 0;
}
/* キューからデータ取り出し&データ削除 */
int deqfromQueue( char *ch )
{
int num;
/* キュー内のデータ登録数を計算 */
if( rear >= top )
num = rear - top;
else
num = MAX - (top - rear);
/* 登録データなしの場合は戻る(※終了はしない)*/
if ( num == 0 ) {
fprintf( stderr, "No data in queue!!\n" );
/* exit( 1 ); */
return -1;
}
/* キューからデータ取出し+topポインタ更新 */
*ch = queue[ top ];
top = (top + 1) % MAX;
return 0;
}
/* キューの先頭データの取り出し */
char peekofQueue()
{
return queue[ top ];
}
/* キューの初期化 */
void initializeQueue()
{
top = 0;
rear = 0;
}
/* キュー操作コマンドのヘルプ表示 */
void print_help()
{
printf( "--- Queue Operation Command ---\n" );
printf( " 0: Exit.\n" );
printf( " 1: De Queue.\n" );
printf( " 2: Display Queue.\n" );
printf( " 3: Initialized Queue.\n" );
printf( " 9: Display this HELP.\n" );
printf( "-------------------------------\n" );
}
/*== main ==*/
int main()
{
char cch; /* char型の文字 */
int ich; /* int型の文字 */
int ires; /* 関数の戻り値 */
int iline; /* 行数カウンタ */
int icolm; /* 文字数カウンタ */
int iblk; /* 入力区分 */
/* =0:コンソールorリダイレクト入力 */
/* =1:コンソール */
/* 入力区分毎のループ処理 */
iblk = 0;
do {
/* 入力区分の開始表示 */
printf( "== Block-%d: Start ==\n", (iblk + 1) );
iline = 0; /* 行数カウンタの初期化 */
icolm = 0; /* 文字数カウンタの初期化 */
printf( "[0:Exit, 9:HELP]=>" ); /* 入力プロンプトの表示 */
/* 1文字ずつ読み込む */
while ( ( ich = getc( stdin ) ) != EOF ) {
/*「1文字目」かつ「入力文字が[LF]以外」の時は改行出力 */
/* ※リダイレクト入力or出力の際に入力プロンプトの表示 */
/* 後が改行されないのを防止するための処置 */
if( icolm==0 && ich!='\n' ){
printf( "\n" );
}
icolm++; /* 文字数カウンタ+1 */
/* 入力文字による処理分岐 */
switch ( ich ) {
case '\r': /* 改行コード(CR,LF)は除く :) */
case '\n': /* 同上 */
/* [LF]の場合は、行数カウンタ+1、文字数カウンタの初期化 */
if( ich == '\n' ){
iline++;
icolm = 0;
}
break;
case '0': /* 0 の場合はプログラム終了 */
printf( "== Exit ==\n" );
exit( 0 );
break;
case '1': /* 1 の場合は1文字デキューして、その文字を表示し、*/
/* キューの内容を表示 */
ires = deqfromQueue( &cch );
if( !ires ){
printf( "deqfromQueue: %c\n", cch );
print_queue_mtrx( queue, top, rear, MAX );
}
break;
case '2': /* 2 の場合はキューの内容を表示 */
print_queue_mtrx( queue, top, rear, MAX );
break;
case '3': /* 3 の場合はキューを初期化 */
printf( "Initialized Queue:\n" );
initializeQueue();
break;
case '9': /* 9 の場合はコマンドヘルプを表示 */
print_help();
break;
default: /* それ以外の場合は1文字エンキューして、*/
/* キューの内容を表示 */
cch = ich;
ires = enqtoQueue( &cch );
if( !ires ){
print_queue_mtrx( queue, top, rear, MAX );
}
break;
}
/* 入力プロンプトの表示 */
if( ich == '\n' ) printf( "[0:Exit, 9:HELP]=>" );
}
/* [EOF]の場合はメッセージ表示 */
if( ich == EOF ){
printf( "\n== End of File ==\n" );
}
/* 入力区分を+1 */
iblk++;
/* 入力区分≧1の時は、標準入力をコンソールに切り替え */
/* ※OSタイプによりコンソールのデバイス名を切替える(コンパイル時)*/
if( iblk >= 1 ){
#if OS_TYPE==0 /* Windows系の場合 */
freopen( "CON", "r", stdin );
#else /* UNIX/Linux/Cygwin系の場合 */
freopen( "/dev/tty", "r", stdin );
#endif
}
} while(1);
return 0;
}
=========================
◎print_queue_mtrx関数のソース
=========================
/*
* printque2.c:キューデータ表示(外部ソース)
*/
#include <stdio.h>
void print_queue_mtrx( char* q, int top, int rear, int qmax )
{
int num;
int cnt;
int pos;
/* キュー内のデータ登録数を計算 */
if( rear >= top )
num = rear - top;
else
num = qmax - (top - rear);
/* キュー内のデータを表示出力 */
if( num == 0 ){
/* キュー内にデータがない場合 */
printf("Queue is empty.\n");
}
else{
/* キュー内にデータがある場合 */
printf("--- Contents of Queue ---\n");
printf(" Data Count = %d\n", num);
printf("-------------------------\n");
for( pos=rear, cnt=0; cnt<num; cnt++ ){
if( pos > 0 ) pos--;
else pos = (qmax - 1);
if(cnt == 0){
printf("%2c < -- Rear (%2d)\n", q[pos], (pos + 1));
}
else if((cnt + 1) == num){
printf("%2c < -- Top. (%2d)\n", q[pos], (pos + 1));
}
else{
printf("%2c\n", q[pos]);
}
}
printf("-------------------------\n");
}
}
=========================
以上です。
補足
ありがとうございます。 質問時点でわかっていませんでした。 指摘されて入力部分を二つに分けようとしているのですが今のところうまくいきません。 提示していただいたプログラムですが、内容を表示する関数であるprint_queue_mtrxにin functinとmultiple definitionエラーが出ます。 分割されている関数、 #include <stdio.h> void print_queue_mtrx(char* q, int top, int rear) { int i; if(top == rear){ printf("Queue is empty.\n"); } else{ printf("--- Contents of Queue ---\n"); for(i = top; i < rear; i++){ if(i == top){ printf("%2c < -- Rear (%2d)\n", q[rear - i + top - 1], rear); } else if(i == rear - 1){ printf("%2c < -- Top (%2d)\n", q[rear - i + top - 1], top + 1); } else{ printf("%2c\n", q[rear - i + top - 1]); } } printf("-------------------------\n"); } } が重複するためだとは思うんですが、単純にそこだけ入れ替えても仕方がないですし・・・。 このプログラムを単体でコンパイルしても freopen("CON","r",stdin); /* 標準入力をコンソールに切り替え */ の部分がどうも機能しているようには思えないのですが・・・。 僕から見ればなんで機能してないのかわかりません・・・。 とりあえず、知らない関数を中心に調べながらやってみようかと思います。