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

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

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

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

Q&A

受付中

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

FRACTAL
FRACTAL

総合スコア0

C

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

4回答

0グッド

0クリップ

342閲覧

投稿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)

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

jimbe

2022/11/28 15:36

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

回答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

総合スコア7336

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

FRACTAL

2022/11/29 14:36

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

2022/11/29 21:47

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

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

総合スコア8087

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

FRACTAL

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 の値を得たいのなら初期化が必要です。

0

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

投稿2022/11/28 15:08

y_waiwai

総合スコア86060

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

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

総合スコア1427

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

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

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

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

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

同じタグがついた質問を見る

C

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