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

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

ただいまの
回答率

90.51%

  • C

    4537questions

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

C言語 コメントの数

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 1,646

marry0129

score -33

標準入力で、/*~*/のようなコメントの数を数えるプログラムです。
一行ごとの読み込みしかわからず、どうやって複数行にまたがるコメントを認識できるのかわかりません。また、/*/ も一つに数えてしまっているみたいです。
具体的にどこをどうしたらいいのか教えて下さい!

以下コードです。

#include<stdio.h>

#define BUFSIZE 1000

int comment(char buf[], int *flag){                    // 関数を用意
    int check = 0;
    int i;

    for (i = 0; '\0' != buf[i]; i++) {                  //受け取った文字が終端文字でなければループ
        if (0 == *flag) {                               //0を受け取る=前に*/があった or いままでフラグがたってない
            if ('/' == buf[i] && '*' == buf[i+1]){      // 受け取った配列に /* があればフラグを立てる flag=1
                *flag = 1;
            }
        } else {
            if ('*' == buf[i] && '/' == buf[i+1]){      // */がきたらフラグを0に戻す
                *flag = 0;
                check = 1;                          //フラグが1,0と変化したらcheck=1
            }
        }
    }

    return check;
}



int main(){
    char buf[BUFSIZE];                                  //文字を入れていく配列
    int line = 0;                                       //コメントの行数を記録する変数
    int flag = 0;                                   //フラグ

    while (NULL != fgets(buf, BUFSIZE, stdin)) {        //標準入力された一行で読み込めるだけ文字を読み込む
        if (0 != comment(buf, &flag))               //comment関数にとぶ  配列とフラグを渡してcheckが1なら
        line++;
    }

    printf("%d/n", line);

    return 0;
}

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • coco_bauer

    2015/11/05 15:19

    「/*/ も一つに数えて」しまうのは、2文字が/*や*/に一致した場合にiを1余分に増加させていないからです。*flga=1;の列の次と、*flag=0;の列の次に、i++:の行を追加すると解決されます。

    キャンセル

回答 4

+2

C言語は原則として「行」の概念がないので、1行ずつ読んで処理するとかなり面倒です。
1文字ずつ処理してはだめでしょうか?
状態として、下記を用意すればできるだろうと思います。

①Idle
②①状態で'/'を検出
③②状態で*を検出
④③状態で*を検出

そして、④の状態で'/'を検出したらコメントの数をインクリメントして①へ戻る感じですね。
なお、②状態で*以外を検出した時に①へ戻す等の処理も忘れないように。

以上だけですと、""や//の中に/* */があると正常にカウントできないですが、それは次の課題とした方がよいと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+2

Chironianさんに賛成します.
状態の数が多くなるのでenumか何かで状態を定義しておいて,
分岐するコードを見やすくしておくと良いと思います.

ただ,もっと大雑把に調べたければ,行で読みこんでもいいと思います.
状態は,コメントアウトの中にいるか,外にいるかだけを使います.
(投稿者さんのコードに近くなります)
①外の状態
 strstr(buf, "/*");がNULL以外を返した→bufの位置をずらして状態②に移行
②中の状態
 strstr(buf, "*/");がNULL以外を返した→コメントカウントを上げて状態①に移行
ただし,1行をバッファ内に必ず収められるという前提が必要です.
これができない場合,バッファの最後に「/」が来て,次に読み込んだバッファが「*」だった,
といった場合に正しく判定できないかもしれないからです.

以下,comment()関数の大雑把な設計です.
同じ行の中に複数のコメントアウトがあることも想定して,
checkは行の中に含まれるコメントアウトの数を返しています.
main()の方も修正しておいてください.
int comment(char *buf, int *flag){
    int check = 0;

    while (1) {
        if (*flag == 0) {
            /* コメントアウトの外にいる */
            if ((buf = strstr(buf, "/*") == NULL) {
                /* この行にはコメントアウトなし */
                return check;
            }
            else {
                /* この行にコメントアウトの開始がある */
                *flag = 1;
                buf += 2; //「/*/」を誤カウントしないために必要
            }
        }
        else {
            /* コメントアウトの中にいる */
            if ((buf = strstr(buf, "*/") == NULL) {
                /* この行ではコメントアウトは終了しない */
                return check;
            }
            else {
                /* この行にコメントアウトの終了がある */
                check++;
                buf += 2;
            }
        }
    }
    /* 本来この行には来ない */
    return 0;
}
コードを見て頂ければわかりますが,冗長な部分がたくさんあります.
char com[][] = {"/*", "*/"};
とかを使えば,この関数は約半分にできます.
const char com[][] = {"/*", "*/"};
int comment(char *buf, int *flag){
    int check = 0;

    while (1) {
        if ((buf = strstr(buf, com[*flag]) == NULL) {
            return check;
        }
        else {
            check += *flag;
            *flag = (*flag) ? 0 : 1; /* フラグを反転 */
            buf += 2; //「/*/」を誤カウントしないために必要
        }
    }
    return 0;
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

//の1行コメントには対応していません。

#include <stdio.h>

int main(){
  /* コメントカウント */
  int count = 0;
  int c1, c2;
  /* 注釈モードをオフに初期化 */
  int c_mode = 0;
  /* 文字定数モードをオフに初期化 */
  int quote1 = 0;
  /* 文字列リテラルモードをオフに初期化 */
  int quote2 = 0;
  
  for ( c1 = getchar(); ( c2 = getchar()) != EOF; c1 = c2 ) {
    if ( !c_mode ) {
      /* 注釈モードがオフのとき */
      /* 文字定数又は文字列リテラルの中で文字 ¥ を検出 */
      if ( (quote1 || quote2) && c1 == '¥¥' ) {
        c2 = getchar();
        continue;
      }
      /* 文字列リテラル以外のところで一重引用符を検出 */
      else if ( !quote2 && c1 == '¥'' )
        quote1 = !quote1;
      /* 文字定数以外のところで二重引用符を検出 */
      else if ( !quote1 && c1 == '¥"' )
        quote2 = !quote2;
      /* 文字定数及び文字列リテラル以外で / と * を検出 */
      else if ( (!quote1 && !quote2) && c1 == '/' && c2 == '*' ) {
        c_mode = !c_mode;
        c2 = getchar();
        count++;
        continue;
      }
    } else {
      /* 注釈の終端か? */
      if ( c1 == '*' && c2 == '/' ) {
        c_mode = !c_mode;
        c2 = getchar();
      }
    }
  }
  return 0;
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/11/10 19:16

    一行コメントに対応していないって、いつの時代のC言語の話でしょうか?
    16年も前のC99の時点で対応しているんですけど…。

    キャンセル

  • 2015/11/11 21:08

    「標準入力で、/*~*/のようなコメントの数を数えるプログラムです。」
    とのことでしたので、問題ないかと

    キャンセル

check解決した方法

-7

/*/も数えず、複数行にまたがってカウントできました

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/11/06 11:23

    どうやって実現できたのでしょうか。同じ問題が発生した人のために解決方法を記載していただけますでしょうか。(他の回答により解決したならそれをベストアンサーに選んでもらえると助かります)

    キャンセル

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

  • C

    4537questions

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