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

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

ただいまの
回答率

90.61%

  • C

    3565questions

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

文字列strの中に、文字cが含まれている個数

解決済

回答 8

投稿

  • 評価
  • クリップ 0
  • VIEW 5,387

reotantan

score 245

文字列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;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

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

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

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 8

checkベストアンサー

+2

1. 

c は文字を読み込むので char 型の方が良いです。
合わせて scanf と str_chnum の引数も直してください。

2.

1回目の scanf でエンターを入力した事により、
2回目の scanf が改行コードを読み込んでしまっています。
2回目の scanf の前で getchar(); して改行コードを読み飛ばしてください。

3.

結果を出力していませんので、main 関数の return の手前で表示しましょう。

4.

while の条件内で *str++ としていますので、
*str が '\0' でなければ、str のアドレス操作が行われます。

while の動作的には正しいのですが、
これでは、while 内の if 文で先頭の文字の分がカウント出来ません。

while の最後で str++; をしましょう。

5.

str_chnum の戻り値は、単に count を返すだけで良いです。

修正例です。
#include <stdio.h>

int str_chnum(const char *str, char c) // 1
{
  int count = 0;

  while (*str) { // 4
    if (*str == c) {
      count++;
    }
    str++; // 4
  }

  return count; // 5
}

int main(void)
{
  char str[100];
  char c; // 1

  puts("type");
  scanf("%s", str);

  getchar(); // 2
  
  puts("type c");
  scanf("%c", &c ); // 1

  printf("%d\n", str_chnum(str, c)); // 3
  return 0;
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

horohoroさんの指摘に加えて、main関数内で
puts("type c");
scanf("%d",&c );
としていますが、ここのscanfの書式指定子が誤っています。ここでは文字列中から探し出す文字を入力させるので、書式指定子は"%d"ではなく、"%c"にします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/06 22:08

    書式指定子も理解が浅いようです、ご指摘ありがとうございます

    キャンセル

+1

ほかの方の指摘以外に・・・
str_chnum()でカウントを返しているようですが、main()で受け取っていませんね?
カウンタを表示させるような処理は要りませんか?
あと、最初のscanf()で読み込んだ後、バッファには改行が残ってしまうので、2回目のscanf()で改行が読み込まれます。なのでfgets()で文字列を読み込んでからscanf()で文字を読み込んだほうがいいと思います。
scanf()の注意については
scanf()の注意事項を参考に。
1文字読み込みならgetchar()かgetc()を使ったほうが確実です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/05 22:24

    returnで返された値をなにかに代入する必要があるという事ですか?
    if(count>=0) return count;のcountはmain関数にあるが、変数にはいっていないという事でしょうか?

    キャンセル

  • 2015/09/06 18:36

    >countはmain関数にあるが
    ・・・がよく分からないのですが・・・
    int count=0;は、関数int str_chnum(const char *str, int c)の中で宣言されているので、main()からは不可視です。
    従って、main()側で受け取る変数(int ansなど)を宣言してans= str_chnum(str,c);という風に受け取らなければ、カウント値は分かりません。

    キャンセル

  • 2015/09/06 19:13

    >reotantanさん
    「スコープ」の概念を確認してみてはいかがでしょう。
    int型変数countは、str_chnum()でのみ使用される、言わば「使い捨ての変数」です。countという変数名およびその値は、main()では使用できません(=「main()からは不可視」)。
    その使い捨ての値を他所でも利用するには、returnで呼び出し元(ここではmain())に教えてあげる必要があります。

    キャンセル

  • 2015/09/06 22:07

    説明が下手くそですいません、解説は理解できました。ありがとうございます

    キャンセル

0

while内でインクリメントしていますよね。
ってことは、最初のcとの比較は1文字目からでなく...(略)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/06 22:11

    そうですね、間違ったコードを書いてしまいました。
    ご指摘ありがとうございます

    キャンセル

0

最初のwhileで、条件判断した後すぐにインクリメントしているので、whileの中のブロックではインクリメントしたあとの値になってしまいます。whileではなくforで条件判断とインクリメントをわければいいかなと思います。
for (; *str; str++) {
  // ...
}
あと、見つからなければcountは0のままなので、最後のif分岐はいらないと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/06 22:10

    はい、確かにそうですね。ありがとうございます

    キャンセル

0

「作ったプログラムが意図通りに動かない。」

こういう時こそデバッガの出番です。
プログラムを書く上でデバッグ作業は避けて通れない面倒な作業と言えます。
ただ、この作業が出来ないようではプログラマとしてはちょっと問題ありです。

参考:
Eclipseでデバッグする
Xcodeでデバッグする
VisualStudioでデバッグする

参考:
EclipseにCDTを追加する手順

XCodeやVisualStudioでのデバッグは特に環境を用意する必要がないので、WindowsやMacの場合は楽に導入できると思います。
Linuxの場合にはEclipseを使うかgdbを使うかで状況が異なりますが、ちょっと手間に感じるとしてもEclipseを用意した方が実際のデバッグ作業が楽になります。

デバッガを使わない方法としては、printfデバッグのように途中の状況を表示させるデバッグ方法があります。
例えば、入力された結果が意図した内容か、関数に渡す値が意図した内容か、ということを実際にprintfで表示して確認するデバッグ方法です。
逐一動作を止めて確認できる状況ばかりではないので、場合によってはこういった方法も必要になります。

int main(void)
{
  char str[100];
  int c;
  puts("type");
  scanf("%s",str);
  puts("type c");
  scanf("%d",&c );

  //(debug print)
  printf("debug: str = %s\n", str);
  printf("debug: c = %x\n", c);

  str_chnum(str,c);
  return 0;
}

実際にそういった方法を使い作業目的を覚えるのも勉強なので、いろいろ実践してみることをお勧めします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/06 22:10

    デバッグ大切ですね、やり方をしっかり覚えます。
    ありがとうございました。

    キャンセル

0

#include <stdio.h>
#include <string.h>

int str_chnum(const char *str, const char c) {
  int count = 0;
  if (str != NULL) {
    const char * p = NULL;
    for (p = str; *p; p++) {
      if (c == *p) {
        count++;
      }
    }
  }
  return count;
}

int main(void) {
  char str[100] = "";
  char c = '\0';

  puts("type str");
  // 一行を読み込む
  fgets(str, sizeof(str) - 1, stdin);
  // 末尾の改行を削除する。
  char * p = strchr(str, '\n');
  if (p) {
    *p = '\0';
  }

  puts("type c");
  scanf(" %c",&c);

  printf("%d 個の '%c' が \"%s\" に含まれています。\n", str_chnum(str, c), c, str);
  return 0;
}

scanf では 空白を含む行全体をよむことができないので、
fscanf をつかっています。また str[] のサイズを超えて文字が書き込まれてしないようにもしています。

参考 
fgets() が改行文字を読み取ると仮定しない
標準入力(キーボード)からの入力を1行取得

また、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/06 22:05

    なるほど,fscanf使ってみます。
    ありがとうございました

    キャンセル

0

まずは、やりたい事をもう一度整理してみると良いと思います。

パッと見で矛盾していると思われる点をいくつか上げると
  • 「文字c」と言いつつ、プログラムでは「int型」で定義している
  • せっかく文字数のカウント結果を関数から「return」しているのに利用していない
  • 関数内の「while」ループでは、終了条件である「文字列の終端」の判定が無い
といった点がうまく動かない原因だと思います。

それと、これは経験を積むうちに身に着く事かも知れませんが、コーディングスタイルがあまり c的 ではないと思いました。

(これは個人的解釈ですが)コーディングスタイルには大きく分けてフォーマット(書式、見た目)に関する部分とイディオム(変数や式の使い方、定石)の2種類があります。

フォーマットについては、優れたフォーマッターがあるのでそちらに任せれば良く、おまり気にする必要はありません。

一方、イディオムを正しく身に着けることは、コーディング力を磨く上で非常に重要です。
いわゆる習慣の問題なので、可能な限り早い段階から意識的に身に着ける努力が必要です。

ここで イディオム と言っているのは、たとえば文字列を先頭から末尾まで1文字ずつ処理する仕方とか文字の比較の仕方などのことで、これらにはいわば定石とも言える書き方があり、それらはどれも洗練されていて無駄がありません。

ですので、まずは自分で一から考えてみるということ自体はとても重要なのですが、一旦動くようになったら、優れた実装例をよく読み(コードリーディング)、単に暗記するのではなく、なぜその書き方が適切なのかという センス を磨くようにお勧めします。

と言いつつ、実は私自身もまだ素人なので…
あまり参考にはならないと思いますが、なるべく元のソースを変えずに修正し、明らかに不要な行を削除したものを記載しておきます。

#include <stdio.h>

int str_chnum(const char *str, const char c)
{
  int count=0;

  while(*str != '\0')        // 誤記訂正。cateyeさんありがとうございます!
  {
    if(*str++ == c) count++;
  }

    return count;
}



int main(void)
{
  char str[100];
  char c;

  puts("type");
  scanf("%[^\n]s",str);
  puts("type c");
  scanf(" %*c%c", &c);

  printf("Result : %d\n", str_chnum(str, c));

  return 0;

主な変更点は
  1.  変数c を char型 へ変更
  2.  whileループは文字列の「終端文字 '\0' を検出するまで」に変更
  3.  カウント結果を返す前のif文による判定は実質的に意味がないので削除
  4.  関数からの戻り値を表示するように変更

なお、scanf関数のフォーマット指定子スキャン集合指定子を追加している意味は下記の通りです。(ご参考)
  変数str:"%s" → "%[¥\n]s":改行以外は読み込む(つまり空白を含めて入力可)
  変数c  :"%c" → "%*c%c"  :直前で実行したscanfのためにバッファに残った改行を読み飛ばす
このようにすると、空白を含む文字列の中に、指定した文字(空白も可)がいくつ含まれているかを検索可能になります。

以上、ご参考になれば幸いです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/06 18:45 編集

    while(*str++ != '\0')←ここで先頭の1文字を読み飛ばしているので・・・
    if(*str==c) count++;←2文字目からの検索になっている?
    # あと・・・好みの問題もあるでしょうが{}はたとえ実行行が一行でもつけておいたほうがいいです。

    キャンセル

  • 2015/09/06 19:24

    cateyeさん、ご指摘ありがとうございます!回答内容を、修正しておきました。

    キャンセル

  • 2015/09/06 22:04

    なるほど、確かに定石を学ぶ事はあらゆるものにおいても重要ですね。
    ありがとうございます

    キャンセル

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

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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

  • C

    3565questions

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