プロが教える店舗&オフィスのセキュリティ対策術

自作のターミナル的なアプリケーションを作成したいと考えているのですが、
通常ターミナルでは、プロンプトの状態でエンターしたらプロンプトが再表示されるのですが、

[例]
$ ←ここでエンター
$ 再表示される

scanfでそれをしようとすると、なにも表示されません。おそらくまだ入力待ちになっています。
scanfの使用上エンターを読み取れないと言っていた人がいたので、代替出来る関数はありませんか?
また、scanfで出きるなら方法を教えて下さい。

ーーー|使用環境|ーーー
OS:Linux(Debian派生)
コンパイラー:GCC

C言語は初めて1年ほどになりますが、途中JavaにいったりHaskellにいったりしてたので、経験は半年分ぐらいです。

よろしくお願い致します。

質問者からの補足コメント

  • 具体的にはどのようにソースを組めばよいのでしょうか。
    main関数のみでもいいので教えていただけませんか?

    No.1の回答に寄せられた補足コメントです。 補足日時:2021/01/02 22:16

A 回答 (6件)

%c ならとれるよ.

    • good
    • 0
この回答へのお礼

ありがとうございます。
反応しました!!
一応認識するのに必要なコードを張っときます。

//以下コード
#include <string.h> //stringヘッダーが必要。stdio.hはインクルード前提

int main(void){
char cmd[100];
do{

printf("$");
scanf("%c", cmd);

if(strcmp(cmd , "\n")==0){ }
}while(1);
}

//コード終了

これで通りました。
一番手っ取り早かったのでベストアンサーにさせていただきます。
ほんとにありがとうございました。

お礼日時:2021/01/07 18:15

一行分を fgets で取ってから sscanf で解析し、


戻り値で目的の入力値が取れたか確認しましょう。

#define N 256

char buff[N], cmd[N], param[N];
while (1) {
_ printf("$ ");
_ fgets(buff, N, stdin); // 安全のために最大桁も指定
_ int n = sscanf(buff, "%s %s", cmd, param);
_ if (n == 0) 単純エンターの場合();
_ if (n == 1) cmdだけ取れた場合();
_ if (n == 2) break; // 無限ループ抜ける
}
cmdとparamが取れた処理(cmd, param);
    • good
    • 1
この回答へのお礼

うーん・・・

わざわざありがとうございます。
しかし、これだと、起動時に、プロンプトが

$ $

のように二つ表示されてしまうんですよね・・・。
いろいろ頑張ってみますが、もし原因がわかるのならおしえてほしいです・・・。

お礼日時:2021/01/08 13:36

私はscanfなんて不便なもの使わないです。


①まず一行メモリに読みこむ
②メモリ上の行を解析する
の方が圧倒的に楽。
    • good
    • 0
この回答へのお礼

まだまだ初心者な面もありますので(というか初心者なので)ちょっとむずかしいですかね。
でもC言語をやってる以上いつかはメモリ操作ぐらい出来ないといけませんよね・・・。

・・・頑張ります。

お礼日時:2021/01/07 18:18

> scanfの使用上エンターを読み取れないと言っていた人がいたので、代替出来る関数はありませんか?



使用OSはLinuxでしょ?
Debian系なら、

sudo apt-get install libedit-dev

してreadline関数を使うのが一番無難だと思いますよ(Windows相手だとこれがオススメ出来ない)。

使う場合はheaderで

#include <editline/readline.h>
#include <editline/history.h>

して(2つ目は履歴編集の為のヘッダですが、便利です)、例えば

char* input = readline("$ ");
add_history(input);

として使えば貴方が要求する仕様に合うと思いますよ。
    • good
    • 1
この回答へのお礼

/usr/bin/ld: /tmp/ccH1dR8D.o: in function `main':
kernel.c:(.text+0x2ff): undefined reference to `readline'
/usr/bin/ld: kernel.c:(.text+0x30f): undefined reference to `add_history'
collect2: error: ld returned 1 exit status

というエラーでコンパイルが止まってしまいました。
原因はなんでしょうか・・・。

お礼日時:2021/01/08 13:43

scanf関数では無くてgetchar関数を使用してみてはどうでしょうか。


C#しか書けないのですが、C#では
System.Console.ReadLine()
の代わりに
System.Console.ReadKey()
を使用しています。
つまり、入力されたキーをstring形式にしたバッファーを作成し、
getcharで1文字1文字を取得しています。

以下 C#のサンプルです。
アルゴリズム的には同じだと思うので参考にしてみてください。

public static unsafe Object GetLine()
{
try
{
//コンソールの一番左に移動
CursorLeft = 0;
//$>と表示
Write("$> ");
//現在の左からの距離を保存しておく
Object tmp = CursorLeft;
//無限ループ
while (true)
{
//文字色を緑に変更
ForegroundColor = ConsoleColor.Green;
//一つキーを押してもらう
ConsoleKeyInfo c = ReadKey(true);
//Enterだった場合は終了
if (c.Key == ConsoleKey.Enter) break;
//削除だった場合はバッファーから1文字削除
else if (c.Key == ConsoleKey.Backspace)
{
//文字数が0以下でバッファーから削除できない場合はビープ音をならす
if (0 < comtmp.Length)
{
comtmp.Length -= 1;
CursorLeft -= 1;
Write(" ");
CursorLeft -= 1;
}
else Beep();
}
//普通の文字だった場合はバッファーに追加
else comtmp.Append(c.KeyChar.ToString());
//文字列の入力を受け取る前の状態にする
CursorLeft = (int)tmp;
//バッファーの文字を表示
Write(comtmp);
}
//入力が終わったはずなので改行する
WriteLine();
}
catch (Exception e)
{
BackgroundColor = ConsoleColor.Black;
ForegroundColor = ConsoleColor.Red;
WriteLine(e);
}
return comtmp.ToString();
}
    • good
    • 1
この回答へのお礼

なるほど、C#についての知識などはありませんが、そのようなアルゴリズムもあったというのが参考になりました。

ありがとうございます。

お礼日時:2021/01/02 22:12

gets/fgetsで行読み込みして、sscanfするとか。

この回答への補足あり
    • good
    • 1

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!