実現したいこと
・文字列sの中に文字cが含まれている個数を返す関数を自作する。
以下のコードのどこが問題であるのかご教授願いたいです。
試したこと
実行自体は問題なくできました。ただ返す値が(本来該当するであろうケースでも)0を返します。
該当のソースコード
#include <stdio.h> int str_chnum(const char* s, int c) { int count = 0; while(*s) { if (*s == c) { count++; } s++; } return count; } int main(void) { char strings[10]; int c; printf("文字列を入力してください:"); scanf("%s", strings); printf("文字を入力してください:"); scanf("%d", &c); printf("文字列の中に、今入力した文字は「%d」個あります", str_chnum(strings, c)); }
実行してみました。
文字列を入力してください:apple
文字を入力してください:a
文字列の中に、今入力した文字は「0」個あります
文字列を入力してください:apple
文字を入力してください:p
文字列の中に、今入力した文字は「0」個あります
文字列を入力してください:apple
文字を入力してください:97
文字列の中に、今入力した文字は「1」個あります
文字列を入力してください:apple
文字を入力してください:112
文字列の中に、今入力した文字は「2」個あります
文字 c の入力方法に問題がありそうですね。
現在取組中ですが、やはりそうですよね。
不安に思う部分はあっていそうで、少し安心しました。
引き続き試してみます。ご回答いただきありがとうございます。
> 実行自体は問題なくできました。
エラーは発生しなかった、という意味でしょうか?
> ただ返す値が(本来該当するであろうケースでも)0を返します。
想定通りの動作をする場合としない場合があるということでしょうか?具体例を示していただけますでしょうか?
①左様でございます。エラーは発生しておりません。
②hoshi-takanori様の実行例にございますように、例えば「apple」と文字列を入力して、文字「a」を入力した場合、「1」を返してほしいのですが、「0」と返されます。
想定している動作をしてくれないので、質問させていただきました。
> 文字列を入力してください:apple
> 文字を入力してください:112 ← ものすごいヒント!!
> 文字列の中に、今入力した文字は「2」個あります
# ただコレ、メモリ溢れおこしてるよねきっと。
「文字を入力してください」なので、
char c;
scanf(" %c", &c);
でしょうね。(format 文字列の先頭にスペースを入れます)
また、strings の読み込みの際に最大長を指定しておくとよいかと。
scanf("%9s", strings);
課題のように思えますが、「文字c」の扱いにchar型を使わない理由があるのでしょうか?
melian様、ご回答いただきありがとうございました。無事想定通りの動作いたしました。
新たに質問が出てしまったのですが、
①なぜstr_chnum関数の仮引数は、int型のcなのに、main関数内の実引数ではchar型のcを渡しても、無事に動作するのでしょうか?
「ずっと「文字」を入力したいが、str_chnum関数の仮引数がint型でchar型を渡せずに困ったなあ、、、」と考えておりました。
②(" %c", &c)でなぜ文字列の先頭にスペースを入れないと、scanf()で止まらずに通り過ぎてしまう(⇔スペースを入れると、無事に入力可能)のはなぜなのでしょう?以前も似たことが起こり、困った覚えがあります。
>以前も似たことが起こり、困った覚えがあります。
その時に調べたりしなかったのでしょうか。
追記
②(" %c", &c)でなぜ文字列の先頭にスペースを入れないと、scanf()で止まらずに通り過ぎてしまう(⇔スペースを入れると、無事に入力可能)のはなぜなのでしょう?以前も似たことが起こり、困った覚えがあります。
⇒解決
① についてですが、コンパイラが自動的に char 型から int 型へ変換してくれるからです。今回は unsigned char 型であることが判っているので問題は起きませんが、signed char 型で負値の場合には未定義動作になる、と ISO/IEC 9899 には記載されていますのでご注意ください。(なので int str_chnum(const char* s, char c) としておく方がよいかと思います)
② については、先頭にスペースを入れておくと入力された文字列の空白文字類(スペース,タブ,改行コードなど)を無視してくれるからです。
その他、蛇足ではありますが、scanf の man には以下の様な記載があります。参考にしてみてください。
> It is very difficult to use these functions correctly, and it is preferable to read entire lines with fgets(3) or getline(3) and parse them later with sscanf(3) or more specialized functions such as strtol(3).
melian様
重ね重ね、ありがとうございます。個人でも調査しておりましたが、ひとまず今のところ疑問に思っている部分はすべて解決することができました。
C言語は奥が深いですね、、、
scanfについても、補足の情報をいただき感謝いたします。ありがとうございました。
また、他の回答者様にも感謝申し上げます。今回の課題と、皆さまのご回答を通じ、疑問に思っていることを減らすことができました。
> C言語は奥が深いですね、、、
数値と文字の区別をちゃんとしましょうというのはどの言語もですね。
scanfの使い方が難しいのは、まあ、Cの特殊事情ではありますが。
melianさんのコメントにある通りですが、「scanfの仕様を熟知している人以外は、端末からの入力にscanfを使ってはいけない」というのはどのC入門書にもちゃんと書いておくべきだと思います。
あと、「scanf fscanf sscanf は必ず返り値を確認する」もか。

回答1件
あなたの回答
tips
プレビュー