文字列strの中に、文字cが含まれている個数(含まれていなければ0とする)を返すという問題でした。
自分でコードを書いてみたのですが、
どこかに問題があるみたいで、問題点を指摘してください。よろしくお願いします
#include <stdio.h> int str_chnum(const char *str, int c) { int count=0; while(*str++) { if(*str==c) { count++; } } if(count>=0) return count; else return 0; } int main(void) { char str[100]; int c; puts("type"); scanf("%s",str); puts("type c"); scanf("%d",&c ); str_chnum(str,c); return 0; }
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答8件
0
ベストアンサー
c は文字を読み込むので char 型の方が良いです。
合わせて scanf と str_chnum の引数も直してください。
1回目の scanf でエンターを入力した事により、
2回目の scanf が改行コードを読み込んでしまっています。
2回目の scanf の前で getchar(); して改行コードを読み飛ばしてください。
結果を出力していませんので、main 関数の return の手前で表示しましょう。
while の条件内で *str++ としていますので、
*str が '\0' でなければ、str のアドレス操作が行われます。
while の動作的には正しいのですが、
これでは、while 内の if 文で先頭の文字の分がカウント出来ません。
while の最後で str++; をしましょう。
str_chnum の戻り値は、単に count を返すだけで良いです。
修正例です。
c
1#include <stdio.h> 2 3int str_chnum(const char *str, char c) // 1 4{ 5 int count = 0; 6 7 while (*str) { // 4 8 if (*str == c) { 9 count++; 10 } 11 str++; // 4 12 } 13 14 return count; // 5 15} 16 17int main(void) 18{ 19 char str[100]; 20 char c; // 1 21 22 puts("type"); 23 scanf("%s", str); 24 25 getchar(); // 2 26 27 puts("type c"); 28 scanf("%c", &c ); // 1 29 30 printf("%d\n", str_chnum(str, c)); // 3 31 return 0; 32}
投稿2015/09/05 13:04
編集2015/09/05 17:01総合スコア101
0
ほかの方の指摘以外に・・・
str_chnum()でカウントを返しているようですが、main()で受け取っていませんね?
カウンタを表示させるような処理は要りませんか?
あと、最初のscanf()で読み込んだ後、バッファには改行が残ってしまうので、2回目のscanf()で改行が読み込まれます。なのでfgets()で文字列を読み込んでからscanf()で文字を読み込んだほうがいいと思います。
scanf()の注意については
scanf()の注意事項を参考に。
1文字読み込みならgetchar()かgetc()を使ったほうが確実です。
投稿2015/09/05 12:53
編集2015/09/05 13:03総合スコア6851
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/09/06 09:36
2015/09/06 10:13
2015/09/06 13:07
0
まずは、やりたい事をもう一度整理してみると良いと思います。
パッと見で矛盾していると思われる点をいくつか上げると
- 「文字c」と言いつつ、プログラムでは「int型」で定義している
- せっかく文字数のカウント結果を関数から「return」しているのに利用していない
- 関数内の「while」ループでは、終了条件である「文字列の終端」の判定が無い
といった点がうまく動かない原因だと思います。
それと、これは経験を積むうちに身に着く事かも知れませんが、コーディングスタイルがあまり c的 ではないと思いました。
(これは個人的解釈ですが)コーディングスタイルには大きく分けて**フォーマット(書式、見た目)に関する部分とイディオム(変数や式の使い方、定石)**の2種類があります。
フォーマットについては、優れたフォーマッターがあるのでそちらに任せれば良く、おまり気にする必要はありません。
一方、イディオムを正しく身に着けることは、コーディング力を磨く上で非常に重要です。
いわゆる習慣の問題なので、可能な限り早い段階から意識的に身に着ける努力が必要です。
ここで イディオム と言っているのは、たとえば文字列を先頭から末尾まで1文字ずつ処理する仕方とか文字の比較の仕方などのことで、これらにはいわば定石とも言える書き方があり、それらはどれも洗練されていて無駄がありません。
ですので、まずは自分で一から考えてみるということ自体はとても重要なのですが、一旦動くようになったら、優れた実装例をよく読み(コードリーディング)、単に暗記するのではなく、なぜその書き方が適切なのかという センス を磨くようにお勧めします。
と言いつつ、実は私自身もまだ素人なので…
あまり参考にはならないと思いますが、なるべく元のソースを変えずに修正し、明らかに不要な行を削除したものを記載しておきます。
c
1#include <stdio.h> 2 3int str_chnum(const char *str, const char c) 4{ 5 int count=0; 6 7 while(*str != '\0') // 誤記訂正。cateyeさんありがとうございます! 8 { 9 if(*str++ == c) count++; 10 } 11 12 return count; 13} 14 15 16 17int main(void) 18{ 19 char str[100]; 20 char c; 21 22 puts("type"); 23 scanf("%[^\n]s",str); 24 puts("type c"); 25 scanf(" %*c%c", &c); 26 27 printf("Result : %d\n", str_chnum(str, c)); 28 29 return 0;
主な変更点は
0. 変数c を char型 へ変更
0. whileループは文字列の「終端文字 '\0' を検出するまで」に変更
0. カウント結果を返す前のif文による判定は実質的に意味がないので削除
0. 関数からの戻り値を表示するように変更
なお、scanf関数のフォーマット指定子にスキャン集合指定子を追加している意味は下記の通りです。(ご参考)
変数str:"%s"
→ "%[¥\n]s"
:改行以外は読み込む(つまり空白を含めて入力可)
変数c :"%c"
→ "%*c%c"
:直前で実行したscanfのためにバッファに残った改行を読み飛ばす
このようにすると、空白を含む文字列の中に、指定した文字(空白も可)がいくつ含まれているかを検索可能になります。
以上、ご参考になれば幸いです。
投稿2015/09/05 16:08
編集2015/09/06 10:24総合スコア5936
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
c
1#include <stdio.h> 2#include <string.h> 3 4int str_chnum(const char *str, const char c) { 5 int count = 0; 6 if (str != NULL) { 7 const char * p = NULL; 8 for (p = str; *p; p++) { 9 if (c == *p) { 10 count++; 11 } 12 } 13 } 14 return count; 15} 16 17int main(void) { 18 char str[100] = ""; 19 char c = '\0'; 20 21 puts("type str"); 22 // 一行を読み込む 23 fgets(str, sizeof(str) - 1, stdin); 24 // 末尾の改行を削除する。 25 char * p = strchr(str, '\n'); 26 if (p) { 27 *p = '\0'; 28 } 29 30 puts("type c"); 31 scanf(" %c",&c); 32 33 printf("%d 個の '%c' が \"%s\" に含まれています。\n", str_chnum(str, c), c, str); 34 return 0; 35}
scanf では 空白を含む行全体をよむことができないので、
fscanf をつかっています。また str[] のサイズを超えて文字が書き込まれてしないようにもしています。
参考
また、fgets(), scanf() 時に CTRL-D が入れられた時でも動作するように、str, c は初期値を入れています。
実行例:
$ ./a.out type str 1234 5678 1234 type c 1 2 個の '1' が "1234 5678 1234" に含まれています。 $ ./a.out type str <--- CTRL-D を押下する type c 0 個の '' が "" に含まれています。
投稿2015/09/05 13:32
総合スコア22324
0
「作ったプログラムが意図通りに動かない。」
こういう時こそデバッガの出番です。
プログラムを書く上でデバッグ作業は避けて通れない面倒な作業と言えます。
ただ、この作業が出来ないようではプログラマとしてはちょっと問題ありです。
参考:
Eclipseでデバッグする
Xcodeでデバッグする
VisualStudioでデバッグする
XCodeやVisualStudioでのデバッグは特に環境を用意する必要がないので、WindowsやMacの場合は楽に導入できると思います。
Linuxの場合にはEclipseを使うかgdbを使うかで状況が異なりますが、ちょっと手間に感じるとしてもEclipseを用意した方が実際のデバッグ作業が楽になります。
デバッガを使わない方法としては、printfデバッグのように途中の状況を表示させるデバッグ方法があります。
例えば、入力された結果が意図した内容か、関数に渡す値が意図した内容か、ということを実際にprintfで表示して確認するデバッグ方法です。
逐一動作を止めて確認できる状況ばかりではないので、場合によってはこういった方法も必要になります。
C
1int main(void) 2{ 3 char str[100]; 4 int c; 5 puts("type"); 6 scanf("%s",str); 7 puts("type c"); 8 scanf("%d",&c ); 9 10 //(debug print) 11 printf("debug: str = %s\n", str); 12 printf("debug: c = %x\n", c); 13 14 str_chnum(str,c); 15 return 0; 16}
実際にそういった方法を使い作業目的を覚えるのも勉強なので、いろいろ実践してみることをお勧めします。
投稿2015/09/05 12:25
退会済みユーザー
総合スコア0
0
最初のwhileで、条件判断した後すぐにインクリメントしているので、whileの中のブロックではインクリメントしたあとの値になってしまいます。whileではなくforで条件判断とインクリメントをわければいいかなと思います。
C
1for (; *str; str++) { 2 // ... 3}
あと、見つからなければcountは0のままなので、最後のif分岐はいらないと思います。
投稿2015/09/05 12:23
総合スコア21735
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。