質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

4回答

873閲覧

scanf関数で文字数が正しくカウントされない

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2022/11/28 14:27

前提

C言語で安全に文字入力を受け取るためのプログラムを書いていました。
scanf関数で改行まで最大255文字をcに入れ、入力された文字数をcharlengthに入れます。
EOFだったら異常終了扱いにします。
最初にEnterが押された、つまり文字が入力されなかったらその旨を伝えます。
最後に文字数を表示します。

実現したいこと

  • 文字数を正しく表示する
  • 文字が入力されなかったことを判定できるようにする

発生している問題・エラーメッセージ

1つ目に、Enterを入力しても何も反応しません。

bash

1■■■■@penguin:~/■■■/■■■■■$ ./myconvert 2アルファベットを入力 : (Enterを入力) 3 (何も反応しなかったのでCtrl+D) 4不正な入力が行われました。プログラムを終了します。 5■■■■@penguin:~/■■■/■■■■■$

2つ目に、文字を入力したときに文字数が正しく表示されません。(下の場合3と出てほしかった)

bash

1■■■■@penguin:~/■■■/■■■■■$ ./myconvert 2アルファベットを入力 : asd 3896 4■■■■@penguin:~/■■■/■■■■■$

該当のソースコード

C

1/* myconvert.c */ 2#include <stdio.h> 3#include <stdlib.h> 4 5int main(void) 6{ 7 char c[0X100]; 8 int charlength; 9 10 printf("アルファベットを入力 : "); 11 if (scanf("%255s[^\n]%n%*[\n]", c, &charlength) == EOF){ 12 printf("\n不正な入力が行われました。プログラムを終了します。\n"); 13 return EXIT_FAILURE; 14 } 15 if (charlength == 0){ 16 printf("入力が行われていません。\n"); 17 } 18 printf("%d\n", charlength); 19 20 return EXIT_SUCCESS; 21}

補足情報(FW/ツールのバージョンなど)

名前バージョン
ChromeOS107.0.5304.110 (Official Build) (64-bit)
Linux(仮想環境)Debian GNU/Linux 11 (bullseye)
gcc10.2.1 20210110 (Debian 10.2.1-6)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/11/28 15:36

scanf でガンバルより 1 文字入力を回すほうが簡単な気がしますが。
guest

回答4

0

scanfは書式指定と入力で順次マッチングを取って、マッチングが取れた部分に変換指定があれば変換して取り込む一方、マッチングしないことが確実になればそこで処理を諦めて以降の取得をせずにリターンするという動作をします。

"%255s[^\n]%n%*[\n]"がどういう入力にマッチするかというと、
%255sで255字までの文字列にマッチし
[で'['にマッチ...ところが、'['は先に文字列にマッチしてしまうので文字列に引き続いて[がマッチするのは255文字文字が続いてその次に[が来たときだけです。なので、この変換指定文字列は254文字以下の文字列が入力された段階(文字列に'\n'が続く状態)で以降はマッチしないことが確定し、%nに対する評価は行われません。
ということで、ローカル変数charlengthにはなんの作用も行われず、未初期化のローカル変数として不定値になります。
最後までマッチさせるとするなら"aaaa...(255文字)...a[^(改行)](改行)改行以外なにかの文字(改行)"と入力すればよいでしょう。"aaaa...(255文字)...a"が%255sにマッチし、[^(改行)]が"[^\n]"にマッチし、%*[\n]に改行がマッチして、改行以外のなにかの文字でマッチングが終了します。最後の改行はなにかの文字を標準入力に押し込むために必要。

また、"%255s"にいきなり改行を与えても、%sはデータ先頭の区切り文字(改行含む)は読み飛ばしますからscanfから抜けません。

多分、"%255[^\n]%n"とかしたかったのかなぁ、と想像はします。
scanfの沼にハマらずに、既に他の回答にありますがfgetsとsscanfあたりに逃げておいたほうが、同じことが楽にできたのではないかと思います。

ところで、この「質問」、よく読むと「何を知りたいか」書いてないんですけど。質問ではなくて不具合報告書ですか?

投稿2022/11/29 12:19

編集2022/11/29 21:43
thkana

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/11/29 14:36

scanf関数について詳しく説明していただきありがとうございます。 そうですね、%255と[^\n]の間にsを入れてしまったのは完全に見落としていました。また、scanf関数ではなくfgets、sscanf、strlen関数を使って処理しようと思っています。 此方が単に心の器が小さい動物であるだけなのかもしれませんが、回答が嫌みたらしい文で始まり、とても不快に感じ傷つきました。私は貴台の儕輩ではありません。言い方を間接的にしたり、ネガティブな内容は後に書いたりするだけでも文全体の印象が変わったと思います。
thkana

2022/11/29 21:47

ご指摘により「後」にしてみました。
guest

0

C

1/* myconvert.c */ 2#include <stdio.h> 3#include <stdlib.h> 4 5int main(void) 6{ 7 char c[256]; 8 int charlength = 0; // ★ 9 10 printf("アルファベットを入力 : "); 11 if (scanf("%255[^\n]%n", c, &charlength) != 1) { 12 if (charlength == 0) 13 puts("\n入力が行われていません。"); 14 else 15 puts("\n不正な入力が行われました。プログラムを終了します。"); 16 return EXIT_FAILURE; 17 } 18 printf("%d\n", charlength); 19 return EXIT_SUCCESS; 20}

これで、Enter のみの場合と、asd という文字列の場合には対応できるはずですが、
256文字以上の文字列が入力された場合にはどういう対応にしたいのですか?

投稿2022/11/28 16:18

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/11/29 04:36 編集

255文字以降の入力は使わずに捨てます。 とりあえずscanfのフォーマット指定子で%*[\n]を使って読み飛ばそうとしました。 質問なんですが、最初のcharlengthの宣言で0で初期化することにはどういう意味があるのでしょうか。
kazuma-s

2022/11/29 06:14 編集

%255[^\n] は '\n' 以外の文字を 1~255文字取り込むという書式です。 Enter だけの入力の場合、1文字も読み込めず、この書式による処理は失敗します。 scanf の実行がそこで打ち切りになるので、次の "%n" は処理されず、charlength に値が設定されません。 if (charlength == 0) で charlength の値を得たいのなら初期化が必要です。
guest

0

正しく表示されない、で投げ出してしまわないで、なにが起こってるのか確認しよう。
cにはなにが入ってるのか確認してみては。

投稿2022/11/28 15:08

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

カラの改行を検出するなら、fgetsーsscanfのパターンの出番。
scanfの%sは非空白な文字が現れるまで戻ってこない。

C

1 char s[280]; 2 printf("アルファベットを入力 : "); 3 fgets( s, 280, stdin); 4 if (sscanf(s, "%255s%n", c, &charlength) == EOF){ 5

投稿2022/11/28 14:54

matukeso

総合スコア1590

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問