K&R 演習1-10 解答 (プログラミング言語C 第2版)

スポンサーリンク

鍛錬 77

K&R 演習1-10 解答 (プログラミング言語C 第2版)

各タブを\tに,各バックスペースを\bに,各バックスラッシュを\\に置き換えながら,入力を出力に複写するプログラムを書け。こうすれば,タブとバックスペースははっきり目に見えるようになる。

B.W.カーニハン D.M.リッチー 石田晴久 訳 『プログラミング言語C 第2版 ANSI 規格準拠』, (共立出版, 2017), pp.25.

スポンサーリンク

プログラム

以下は、タブを \t に、バックスペースを \b に、バックスラッシュを \\ に置き換えながら、入力を出力に複写するプログラム、kr_1_10.c です。

#include <stdio.h>

int main(void)
{
	int c;
	
	// ストリームからデータを取得
	while ((c = getchar()) != EOF) {
		// タブの場合
		if (c == '\t') {
			c = '\\';
			putchar(c);
			c = 't';
			putchar(c);
		}
		// バックスペースの場合
		else if (c == '\b') {
			c = '\\';
			putchar(c);
			c = 'b';
			putchar(c);
		}
		// バックスラッシュの場合
		else if (c == '\\') {
			c = '\\';
			putchar(c);
			putchar(c);
		}
		// その他の場合
		else
			putchar(c);
	}
	
	return 0;
}
スポンサーリンク

上記プログラムを実行して確認する際の問題点

上記のプログラム kr_1_10.c を実行して確認する際、「バックスペースをどのようにして送信するのか」という問題点が存在します。

タブとバックスラッシュについて

問題なし。

「タブキー」もしくは「バックスラッシュキー」を押下後に、「エンターキー」を押下すれば、タブ(‘\t’) もしくは バックスラッシュ(‘\’) のデータを送信することができる。

バックスペースについて

問題あり。

「バックスペースキー」を押下しても、ターミナルに入力中の他のデータが1文字削除されるだけで、バックスペースのデータ(‘\b’)を送信することができない。
 
上記問題点の例:

例として、以下の順序で実行した場合について考えます。

  1. ABC と入力
  2. キーボードの「バックスペースキー」を押下
  3. キーボードの「エンターキー」を押下
  • 送信したいデータ
    ‘A (0x41)’
    ‘B (0x42)’
    ‘C (0x43)’
    ‘バックスペース (0x08)’
    ‘改行コード (0x0a)’
  • 実際に送信されるデータ
    ‘A (0x41)’
    ‘B (0x42)’
    ‘改行コード (0x0a)’

 
上記の例を実際に実行して確認:

以下は、上記の例を実際に実行して確認しています。

ABC、バックスペースキー(‘\b’)、エンターキー(‘0x0a’) の順で押下しても、AB と改行コード(‘0x0a’) しか送信できていません。

***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ gcc -Wall -Wextra kr_1_10.c -o kr_1_10
***@ubuntu:~/***/test/c$ ./kr_1_10
AB 
AB
スポンサーリンク

バックスペース(‘\b’)のデータを送信する方法を確認する

バックスペースキーを押下しなくても、バックスペース(‘\b’)のデータを送信する方法を確認します。

まずは、ターミナルにおけるバックスペース(‘\b’)の機能について確認します。

MANページを確認

BASH の MANページ を確認すると、ターミナルにおけるバックスペース(‘\b’)の機能は、入力の読み込みを処理するライブラリである readline が使用されています。

バックスペース(‘\b’)の機能は、その readline のコマンドのうちの一つである、backward-delete-char が使用されているようです。

キー割り当てを確認

次に、readline のコマンドである backward-delete-char が、どのキーに割り当てられているのかを確認します。

BASH の MANページ を確認すると、組み込みコマンドである bind を使用することにより、以下に示す内容を実行できるようです。

  • readline の、現在のキー割り当てと関数割り当てを表示
  • キーシーケンスを、readline の関数やマクロに割り当て
  • readline の変数を設定

今回は readline のキー割り当てについて、どのキーに backward-delete-char が割り当てられているのかを確認するため、bind にオプションの -P を付加します。

以下は、backward-delete-char がどのキーに割り当てられているのかを確認しています。

***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ bind -P | grep backward-delete-char
backward-delete-char can be found on "\C-h", "\C-?".
forward-backward-delete-char is not bound to any keys

 
上記に示した通り、backward-delete-char は、Ctrl+h と Ctrl+? に割り当てられているようです。

よって、ターミナルでバックスペース(‘\b’)のデータを送信するには、Ctrl+h を押下すればいいことが分かりました。

スポンサーリンク

実行結果

以下は、前述したプログラム kr_1_10.c を実行し、次の通り押下しています。

「AAA(タブキー)BBB(Ctrl+h)CCC(バックスラッシュキー)DDD(エンターキー)」

***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ gcc -Wall -Wextra kr_1_10.c -o kr_1_10
***@ubuntu:~/***/test/c$ ./kr_1_10
AAA	BBB^HCCC\DDD
AAA\tBBB\bCCC\\DDD

 
上記に示した通り、タブを \t に、バックスペースを \b に、バックスラッシュを \\ に置き換えながら、入力を出力に複写することができました。

タイトルとURLをコピーしました