C言語関係掲示板

過去ログ

No782 キー入力とリダイレクトの併用

[戻る] [ホームページ]
No.9724

リダイレクトのせいでscanfが使えず困っています。
投稿者---スバル(2003/10/13 06:17:13)


fgetsのstdinで(表現おかしくて済みません)リダイレクトを使ったところ、その前のscanfでキーボードからの入力ができなくなってしまいまして困っています。
"リダイレクト scanf"でググったのですが、解決策が見当たりませんでしたので、質問させて頂きました。
実行時に何かもう一工夫すればうまく入力できるような気もするのですが。

どなたかご教授願えませんでしょうか?

※scanfを使わず、プログラムに直接値(int型整数)を入れたらちゃんと動いてくれます。
※ソースは長すぎると思ったので張りませんでした。

No.9727

Re:リダイレクトのせいでscanfが使えず困っています。
投稿者---ともじ(2003/10/13 16:07:24)


こんにちは。

>fgetsのstdinで(表現おかしくて済みません)リダイレクトを使ったところ、
>その前のscanfでキーボードからの入力ができなくなってしまいまして困っています。

たとえば、下のようなプログラムを実行し、結果をリダイレクトすると、
どうなりますか。画面に「整数を2つ入力してください。」と表示する
ことはできませんが、キーボードから整数値を2つ入力すると、リダイレクト
で指定したファイルに実行結果を得ることができるはずです。

もし、「整数を2つ入力してください。」の部分は画面に表示したいのなら、
fprintf(stderr, "整数を2つ入力してください。\n");
としてみてください。stderrへの出力はリダイレクトでファイルへ出力されません。
#include <stdio.h>

int main(void)
{
    int a, b;
    
    printf("整数を2つ入力してください。\n");
    scanf("%d%d", &a, &b);
    printf("%d+%d=%d\n", a, b, a+b);
    
    return 0;
}


ところで、そのプログラムでリダイレクトしないとどうなりますか。
scanfのあとでstdinに対してfgetsすると、scanfが食い残した'\n'を
入力してしまい、正常な入力ができないように思いますが。

No.9729

Re:リダイレクトのせいでscanfが使えず困っています。
投稿者---スバル(2003/10/13 16:52:17)


レスありがとうございます。

>結果をリダイレクトすると、

うーんと…私は実行時に

01.exe < seiseki.txt

としてリダイレクトで入力ファイルを指名しつつ、データ数だけはキーボードから打ち込むという風にしたかったのですが、リダイレクトって言葉の使い方間違ってましたかね…

>ところで、そのプログラムでリダイレクトしないとどうなりますか。

済みませんです。重要なとこ抜けてましたね。
scanf実行の後に呼び出した関数の中でfgetsで入力ファイルをリダイレクト(?)したいのですが、scanf入れて実行すると、(リダイレクトしたいるので当たり前ですが)入力待ちの画面にならずに勝手に最後まで行ってしまいます。もちろんデータ数も入力ファイルもきちんとは読み込まれずに、データは最初の一行の後半だけ読み込まれています。

リダイレクトしないと、入力待ち画面にはなるのですが、それだとデータ数分全部打ち込まなくてはいけないと思うのですが…リダイレクトせずに入力ファイルごと指定する方法などは無いのでしょうか?

FILEポインタを使おうとも思ったのですが、関数の中でstdinを使っているので、*argv[1]も関数の引数にしないといけなくて、それでは駄目なのです(関数の引数は構造体とデータ数と決まっているので)

説明下手で済みません。

私のソース張った方が早いですかね…無駄に長いので自重してるのですが。

No.9730

Re:リダイレクトのせいでscanfが使えず困っています。
投稿者---YuO(2003/10/13 17:10:48)


>うーんと…私は実行時に
>01.exe < seiseki.txt
>としてリダイレクトで入力ファイルを指名しつつ、データ数だけはキーボードから打ち込むという風にしたかったのですが、リダイレクトって言葉の使い方間違ってましたかね…

リダイレクトっていうのは,標準入出力を特定のデバイス(ファイル含む)に置き換えるものです。


>FILEポインタを使おうとも思ったのですが、関数の中でstdinを使っているので、*argv[1]も関数の引数にしないといけなくて、それでは駄目なのです(関数の引数は構造体とデータ数と決まっているので)

関数の設計を間違えているのですから,関数のインターフェースを変更すべきです。
根本的に「できない」ものはいくら頑張っても「できない」ままです。

#環境がわかれば,キーボードのデバイス名がわかるかもしれませんが……。

あと,*argv[1]を渡しても意味はありません。
argv[1]を渡す必要があります。


No.9733

ご指摘ありがとうございました
投稿者---スバル(2003/10/13 17:41:41)


ご指摘ありがとうございます。

>関数の設計を間違えているのですから,関数のインターフェースを変更すべきです。
>根本的に「できない」ものはいくら頑張っても「できない」ままです。

何かうまくいく方法があるのかと思ってお聞きしたのですが、やはり駄目なものは駄目なのですか。
FILEポインタを関数の引数に加えて、リダイレクトを使わないという方向で何とか許してもらおうかと思います。(課題より引数の数が増えてしまいましたが)

ということで私がコレで許してもらおうかと思ってるソースです。最後なので長いですがマナー(?)として張ります。


#include<stdio.h>
#include<stdlib.h>

#define N 2500

struct student{
int num;
char name[18];
int score;
}A[N];

void exe00(struct student A[],int n,FILE *fp); /* 引数が増えてしまいました */
void exe03(struct student A[],int n);

main(int argc,char *argv[])
{
int n;
FILE *fp;
fp=fopen(argv[1],"r");

printf("\nデータ数nを入力せよ\nn=");
scanf("%d",&n);

exe00(A,n,fp);

printf("\nデータを単純選択整列(得点で降順)\n");
printf("同点の場合は学籍番号順(昇順)\n\n");
printf("以下単純選択整列の様子を示す\n\n");

exe03(A,n);

return 0;
}

void exe00(struct student A[],int n,FILE *fp)
{
int i,j;
char a[29],b[4],c[3];
for(i=0;i<n;i++){
fgets(a,30,fp);
for(j=0;j<4;j++)
b[j]=a[j];
A[i].num=atoi(b);
for(j=5;j<23;j++)
A[i].name[j-5]=a[j];
for(j=24;j<27;j++)
c[j-24]=a[j];
A[i].score=atoi(c);
}
for(i=0;i<n;i++)
printf("%4d %18s %3d\n",A[i].num,A[i].name,A[i].score);
}

void exe03(struct student A[],int n)
{
int i,j,hikaku=0,irekae=0;
char a[N]="|12345678",b;
struct student B;

puts(a);
for(i=0;i<n;i++){
for(j=i+1;j<n;j++,hikaku++)
if(A[j].score>A[i].score){
B=A[i];
A[i]=A[j];
A[j]=B;
irekae++;
b=a[i+1];
a[i+1]=a[j+1];
a[j+1]=b;
printf("%s %d番と%d番のデータを入れ換え\n",a,A[i].num,A[j].num);
}
else if(A[j].score==A[i].score&&A[j].num<A[i].num){
B=A[i];
A[i]=A[j];
A[j]=B;
irekae++;
b=a[i+1];
a[i+1]=a[j+1];
a[j+1]=b;
printf("%s %d番と%d番のデータを入れ換え\n",a,A[i].num,A[j].num);
}
b=a[i];
a[i]=a[i+1];
a[i+1]=b;
puts(a);
}
putchar('\n');

for(i=0;i<n;i++)
printf("%4d %18s %3d\n",A[i].num,A[i].name,A[i].score);

printf("\n●比較回数=%d\n●入れ換え回数=%d\n",hikaku,irekae);
}


次は入力ファイルの一つです。一行に一人の情報が記述されており、各行は
1〜4 文字目 学籍番号(右詰め)
5文字目 空白
6〜23文字目 氏名(左詰め)
24文字目 空白
25〜27文字目 成績(右詰め)
となっています。


1 安室_奈美恵 56
2 一色_紗英 82
3 小沢_真珠 56
4 菅野_美穂 56
5 佐藤_藍子 82
6 鈴木_沙理奈 26
7 松_たか子 100
8 山口_リエ 90


ソースは突っ込みどころ満載かも知れませんがw
レス下さったお二方ともありがとうございましたm(_ _)m


No.9732

Re:リダイレクトのせいでscanfが使えず困っています。
投稿者---かずま(2003/10/13 17:39:49)


> ※ソースは長すぎると思ったので張りませんでした。

scanf と fgets だけの問題なのだったら、その部分だけを取り出した簡単な
プログラムを作って、同じ現象が起こることを示せばいいんじゃないんでしょうか。

次のプログラムは参考になりますか。
int main(void)
{
    int val; char buf[256];
    FILE *con = fopen("con", "r");  /* Unix なら "/dev/tty" */

    if (fscanf(con, "%d%*c", &val) != 1) return 1;
    printf("val = %d\n", val);
    while (fgets(buf, sizeof buf, stdin))
        fputs(buf, stdout);
    return 0;
}


No.9734

まさにコレです。どうもありがとうございます
投稿者---スバル(2003/10/13 18:22:53)


>scanf と fgets だけの問題なのだったら、その部分だけを取り出した簡単な
>プログラムを作って、同じ現象が起こることを示せばいいんじゃないんでしょうか。

おっしゃる通りですね…済みませんでした。

>次のプログラムは参考になりますか。

はい!はい!ばっちり参考にさせていただきました。私がしたかったことはまさにコレでした。

"con"
何かと思って調べましたら
con   ・・・コンソール(キーボード/スクリーン)
なるほど他の文字じゃだめなわけだ…ここがミソだったのですね(済みません勉強不足で)

これでほんとのほんとに問題が解決しました。ありがとうございました。

No.9749

Re:まさにコレです。どうもありがとうございます
投稿者---RAPT(2003/10/13 23:58:13)


sprintf()を使います。

int main()
{
  long value = 12345;
  char buff[100] = {0};
  sprintf(buff, "|%ld", value);
  printf("%ld -> \"%s\"\n", value, buff);
  return 0;
}


No.9753

二個目の質問削除してしまってすみません
投稿者---スバル(2003/10/14 01:30:36)


一応消す前の質問張っておきます

No.9733
に添付した(長くてすみません)プログラムの関数exe03の中で
char a[N]="|12345678"
と初期化しているところがあると思うのですが、これを直接プログラムに書くのじゃなくて、1〜n(キーボードから打ち込んだデータ数)までを入れられるようにできないかとforループなどを使ってやってみたのですが、charにint型数字を入れられなくて、固まりました。
"|"を使って整列の様子を表示したいので、charでいきたいと思うのですが、何かいい入れ方がありませんでしょうか?


質問が変わったので新スレに直そうと思ったら、何かよさげなサイトがあったのでそれで何とかできないか頑張ってました。

>sprintf()を使います。

なるほど!その手がありましたか。しかし、この場合11とかはどうですか?

先ほどまで私がやっていたのはASCIIコードに変換して入れるやり方だったのですが、それでもやはり10以上が入れられなくて、何とかならないかと頑張ったのですが、やはりできませんで…

結局int配列にして0が現在地ということでいこうかと思っていたのところでした。

ってあれ?charって元々10以上の数字って入れられませんでしたっけ?(根本的問題が…)

No.9783

Re:二個目の質問削除してしまってすみません
投稿者---RAPT(2003/10/15 00:40:33)


何か、目茶目茶混乱していませんか?

char が signed char か unsigned char なのかは、処理系に依存しますが、
signed char : -128 〜 127
unsigned char : 0 〜 255
です。

> char a[N]="|12345678"
とあったので、
a[0] = '|';
a[1] = '1';
a[2] = '2';
a[3] = '3';
a[4] = '4';
a[5] = '5';
a[6] = '6';
a[7] = '7';
a[8] = '8';
a[9] = '\0';
といったことをしたいのだと思ったのですが、違ったのですか?
上記はあくまで、配列です。

> 先ほどまで私がやっていたのはASCIIコードに変換して入れるやり方だったのですが、
> それでもやはり10以上が入れられなくて
char b[1] = '1' - '0';
char b[2] = '2' - '0';
 :
などとしていたのでしょうか。それにしても、これは「ASCIIコードに変換」とは呼びませんが。


char c[1] = atoi("1");
char c[2] = atoi("2");
 :
char c[10] = atoi("10");
こういった処理を期待しているのでしょうか。