ソースコードの行数

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
mii

ソースコードの行数

#1

投稿記事 by mii » 15年前

初めまして。miiと申します。

課題でc言語のみを扱うステップ数をカウントするプログラムを作成するのですが、
良い方法が思いつかず困っています。

環境はborland C 5.5でWinVistaになります。

総ステップと実行ステップを求めるというもので、、
実行ステップを求める際にどうすればよいのか教えて頂きたいです。

実行ステップについてはコメント行と空白行を除いた行数となり

1 : /*コメント*/ printf("hello")
2 : printf("hello")
3 : // printf("hello")

なら実行ステップは1行目と2行目になるような仕様です。

総ステップ数と空白行の部分は何とかなりそうなのですが、
コメントの部分で/**/の処理をどうすればよいか分からないので、
具体的な考え方を教えて頂ければと思います。

よろしくお願いします。

Dixq (管理人)

Re:ソースコードの行数

#2

投稿記事 by Dixq (管理人) » 15年前

一番簡単な方法としてはfgetcを使ったプログラムでしょうか。
一文字ずつ取ってきて、単純に改行コードが来た数だけカウントしてやれば
行数が解ると思います。
新しい行において、何か文字が来る前に改行コードが来たら空白行だとわかるでしょう。
また、/**/についてはフラグを用意したらいいのではないでしょうか。
/*が来たら「カウントしないフラグ」を立て、改行コードが来てもステップ数をカウントしないようにします。
*/が来たら「カウントしないフラグ」をおろし、改行コードが来たらステップ数をカウントするようにします。
これで出来るのではないでしょうか?

non

Re:ソースコードの行数

#3

投稿記事 by non » 15年前

初めまして。
学校の課題の場合、どの辺まで学んで、何を使って良いかが問題になります。すなわち、先生が
その課題で、何を学ばせようとしているかがあるはずです。
わかりやすくいえば、ファイルの入出力をどうするのか、ポインタは学んだのかなどです。
また、あなたがどれくらい習得しているかも知りたいところです。
>総ステップ数と空白行の部分は何とかなりそうなのですが
ということですので、総ステップ数(行数だとおもうけど)を求めるプログラムを
作って、添付してください。

mii

Re:ソースコードの行数

#4

投稿記事 by mii » 15年前

おはようございます。
とりあえず総ステップ数を求めてみました。

ポインタ、ファイル等までは学習しています。
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE    *fp;        // ファイルポインタ
    int    lineCnt;    // 行数
    int    blankLines;    // 空白行
    int    c;
    
    // ファイルオープン
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    
    lineCnt = 1;
    // 総ステップ数と空白行を求める
    while((c = fgetc(fp)) != EOF) {
        
        // 改行文字の場合行数を増やす
        if (c == '\n') {
            lineCnt++;
        }
    }
    
    printf("総ステップ数 = %d", lineCnt);
    
    return 0;
}

non

Re:ソースコードの行数

#5

投稿記事 by non » 15年前

問題の確認ですが、
1 空白行とは、TABも含みますよね。
2 最終行は、EOFのみの行でしょうか?それとも、文字があって行の終わりにEOFでしょうか?
  または、どちらでも正しく計数する必要があるのでしょうか?

mii

Re:ソースコードの行数

#6

投稿記事 by mii » 15年前

その通りです。明記しておらずすみません。

1については空白行はTAB、スペースともに含みます。
2についてはどちらとも正しく計算する必要があります。

non

Re:ソースコードの行数

#7

投稿記事 by non » 15年前

最初に、空白行(TABを含む)をカウントするプログラムのみ作りましょう。

考え方としてはDixqさんが仰るようにフラグを使います。
まず、フラグの宣言です。
int space_flag=0;
カウントをクリアしておきましょう
blankLines=0;
スペースやTAB以外の文字が出てきたら、space_flag=1;にします。
改行文字のときに、space_flag==0のままならblankLinesをカウントアップします。
space_flag=0;に戻します。

ただし、プログラムするときは、
改行文字かチェックして、それ以外の場合に、空白文字以外かとチェックした方が簡単です。

そこまで、作ってみてください。
なお、EOFの場合分けは不明なので、まだ考えていません。

mii

Re:ソースコードの行数

#8

投稿記事 by mii » 15年前

nonさんお世話になってます。
取りあえず作ってみました。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
    FILE    *fp;                // ファイルポインタ
    int        lineCnt;            // 行数
    int        blankLines = 0;        // 空白行
    int        space_flag = 0;
    int        ch;
    // ファイルオープン
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    lineCnt = 1;
    // 総ステップ数と空白行を求める
    while((ch = fgetc(fp)) != EOF) {
        // 改行文字の場合行数を増やす
        if (ch =='\n') {
            lineCnt++;    
            // 改行の後が空白だけなら
            if (space_flag == 0) {
                blankLines++;
            }
            space_flag = 0;
        }
        // 空白文字以外なら
        else if (!isspace(ch)) {
            space_flag = 1;
        }
    }
    printf("総ステップ数 = %d", lineCnt);
    printf("総空白数 = %d", blankLines);
    
    return 0;
}

Dixq (管理人)

Re:ソースコードの行数

#9

投稿記事 by Dixq (管理人) » 15年前

おぉ、もう出来そうじゃないですか。
後は私が上で言ったようにコメント部無視すれば完成ですね。

ヒント:
今読み取った文字が*で、一つ前に読み取った文字が/ならコメント開始ですね。終了はその逆。一つ前に読み取った文字は、新しい変数を一つ用意してループの最後に記憶させてやればOKです。

non

Re:ソースコードの行数

#10

投稿記事 by non » 15年前

さて、コメントはやっかいですね。
私が思いつく方法は3通り。

方法1 Dixqさんの方法。 1文字ずつ、処理していく。力業 。
方法2 配列(または動的に確保したメモリ)に1行分格納し、1行ずつ処理していく。
方法3 コメントを削除したファイルを中間ファイルとして保存し、再度読み込み、行数を数える。

一番簡単なのは方法3、一番ややこしいのが方法1です。どうします?

mii

Re:ソースコードの行数

#11

投稿記事 by mii » 15年前

管理人さんお世話になります。
一応書いてみたのですが、グチャグチャでわからなくなってしまいました(汗
/* ~ */の間をコメント、そうでなければなどと考えていたら困ってきました。
どんな感じにすればよいでしょうか?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main(void)
{
    FILE    *fp;            // ファイルポインタ
    int  lineCnt;           // 行数
    int  blankLines = 0;    // 空白行
    int  space_flag = 0;
    int  comentLines = 0;
    int  cntOff = 0;
    int  ch;
    int  back;
    
    // ファイルオープン
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    
    lineCnt = 1;
    // 総ステップ数と空白行を求める
    while((ch = fgetc(fp)) != EOF) {
        
        // 改行文字の場合行数を増やす
        if (ch =='\n' && cntOff != 1) {
            lineCnt++;
            
            // 改行の後が空白だけなら
            if (space_flag == 0) {
                blankLines++;
            }
            space_flag = 0;
        }
        // コメントの処理
        else if (ch == '*') {
            // 前の文字が/なら
            if (back == '/') {
                cntOff = 1;
            }
        }
        // コメント終了
        else if (ch == '/') {
            if (back == '*') {
                cntOff = 0;
            }
        }
        // 空白文字以外なら
        else if (!isspace(ch)) {
            space_flag = 1;
        }                                                                                                                                       
        back = ch;
    }
    
    printf("総ステップ数 = %d\n", lineCnt);
    printf("総空白数 = %d\n", blankLines);
    printf("コメント行数 = %d\n", comentLines);
    /*kkk*/ 
    printf("ss");
    return 0;
}

non

Re:ソースコードの行数

#12

投稿記事 by non » 15年前

方法1の力業にしましたか。面倒だな・・・・。
とりあえず、方法3で作って、考え方を整理してから方法1を考えた方がいいと思います。
いきなり、方法1で作るなら、私はパス。

mii

Re:ソースコードの行数

#13

投稿記事 by mii » 15年前

いきなり力業にしましたが、確かにフラグ等も多くてわかりにくくなってしまいました。
とりあえず方法3でやってみたいと思うのですが、教えて頂けますでしょうか?

ちなみに処理ステップ数というのが追加されまして、
実行ステップ数のうち(プリプロセス行・中カッコのみの行を除いたステップ数)
という3種類を求めなければならない仕様になりました(泣

non

Re:ソースコードの行数

#14

投稿記事 by non » 15年前

方法3ならお手伝いしましょう。

まず、仕様をはっきりしましょう。

コメントには次のような場合があると思われます。
または、その複合です。
/* abc */

a=5;/*  abc */

/* abc */ a=5;

/* abc
   def
   ghi  */

// abc
a=5; // abc
さらに、
コメントのネストは面倒だから考えない。
ダブルコーテーションの間にあるコメントも面倒だから考えない。
という条件にしたいのですが。
これで、もれがないでしょうか?

それから追加された仕様ですが
>実行ステップ数のうち(プリプロセス行・中カッコのみの行を除いたステップ数)
意味がよくわかりません。{や}だけの行を除けということでしょうか?

PS
普通の授業の課題にしては結構面倒な課題ですね。
まさかとおもうけど、このあと、コンパイラを作ろうという話じゃないでしょうね。

mii

Re:ソースコードの行数

#15

投稿記事 by mii » 15年前

最終的には総ステップ数、実行ステップ数、処理ステップ数
を3つにわけて算出したいのですが、

a=5;/* abc */
a=5; // abc
/* abc */ a=5;

例えば上記のようなコメントは総ステップと実行ステップと処理ステップにカウントすればOKです!

// abc
/* abc */
/*
ab
*/

上記ならば総ステップ数だけカウントされればOKです!

} //abc

上記ならば総ステップと実行ステップにカウントされればOKです!

1.総ステップ数 (すべての行数)
2.実行ステップ数 (コメント行および空白行を除いた行数)
3.処理ステップ数 (実ステップ数のうち、プリプロセッサ行・
中カッコのみの行を除いたステップ数)

こんな感じです。

>さらに、コメントのネストは面倒だから考えない。
ダブルコーテーションの間にあるコメントも面倒だから考えない。という条件にしたいのですが。
これで、もれがないでしょうか?

大丈夫です!

>実行ステップ数のうち(プリプロセス行・中カッコのみの行を除いたステップ数)
意味がよくわかりません。{や}だけの行を除けということでしょうか?

これは実行ステップから先頭に#が付くもの(#ifや#include等です)と
中カッコは{や}だけというnonさんの見解で合ってます!

>PS 普通の授業の課題にしては結構面倒な課題ですね。
それはたぶん...ないと思います(笑

長くなってすみません。

non

Re:ソースコードの行数

#16

投稿記事 by non » 15年前

まず、miiさんのプログラムから無駄なモノを省き、ファイルを読み込んで
1文字遅れで標準出力するプログラムにしました。
(最初の段階では、ファイルに出力せず、標準出力にしています)
理解できますでしょうか?
最初の1文字目を呼んだときは、1個前の文字がないため、出力しないように
変数startを使っています。
また、EOFにぶつかったとき最後の文字はまだ出力していないので、whileの外で
最後の文字を出力します。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main(void)
{
    FILE    *fp;            // ファイルポインタ
    int  cntOff = 0;
    int  ch;
    int  back=0;
    int start=1;
    // ファイルオープン
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    while((ch = fgetc(fp)) != EOF) {
        /* ここに処理を加えていく */


        if(start==0 && cntOff==0)
            putchar(back);
        start=0;
        back = ch;
    }
    if(start==0 && cntOff==0)
        putchar(back);
    
    fclose(fp);
    return 0;
}
さて、ここで、コメントになれば、cntOffを0以外にして、コメントでない間はcntOff=0に
するプログラムを作っていきます。

まずは、簡単なのは
// abc
a=5; // abc
のような//のコメントです。ここを最初に作りましょう。

今の文字chが'/'で1個前も'/'なら cntOff=1にします。

cntOff=1で1個前が改行なら cntOff=0 に戻します。

ここまで入力して、実行したら、//のコメントが消えれば正解です。

ここまで、できたら、プログラムを貼り付けてください。

mii

Re:ソースコードの行数

#17

投稿記事 by mii » 15年前

nonさんありがとうございます。
一応コメントが消えましたので貼ります。
#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>



int main(void)

{

    FILE    *fp;            // ファイルポインタ

    int  cntOff = 0;

    int  ch;

    int  back=0;

    int start=1;

    // ファイルオープン

    if ((fp = fopen("a.c", "r")) == NULL) {

        printf("open error\n");

        exit(EXIT_FAILURE);

    }

    while((ch = fgetc(fp)) != EOF) {

        /* ここに処理を加えていく */
        if (ch == '/' && back == '/') {
            cntOff = 1;
        }
        
        if (cntOff == 1 && back == '\n') {
            cntOff = 0;
        }

        if(start==0 && cntOff==0)

            putchar(back);

        start=0;

        back = ch;

    }

    if(start==0 && cntOff==0)

        putchar(back);

    

    fclose(fp);

    return 0;

}

non

Re:ソースコードの行数

#18

投稿記事 by non » 15年前

では次に、/*~*/のコメントです。
基本的な考え方は//と同じです・
/*のとき cntOff = 2 にしましょう。

*/のとき cntOff=0 にすればよさそうですが、まだ*/の2文字を
出力したくないので、int count を用意して
cntOff=-1にしておいて、
count=2にします。

cntOff=-1のとき
count==0になったらcntOff=0にします。
そうでなければ、countを減らします。

ここまでで、コメントが消えると思いますが、コメントが複数行にわたったときは
改行は消したくありません。ですから、'\n'のときは、cntOffが何であってもputcharする
ように変更します。

じゃ、ここまで。

たかぎ

Re:ソースコードの行数

#19

投稿記事 by たかぎ » 15年前

この問題は、まともに考えると結構面倒ですね。
引用符やコメントのネストも本来は処理すべきですし、それ以外にも三文字表記や二文字表記も考慮しなければなりません。

//形式のコメントや前処理指令は、行末に\(または??/)がある場合には次の行に続くことになります。
前処理指令は、#のほか、??=や%:もあり得ます。
文字列リテラルの処理は、文字列中のエスケープとして、\以外に??/を考慮しなければなりません。
中かっこは、{と}の他に、<%と%>、または??<と??>を考慮しなければなりません。

non

Re:ソースコードの行数

#20

投稿記事 by non » 15年前

たかぎさん
そうですよね。こんな面倒なの考えたくないです。条件を絞らないと。

mii

Re:ソースコードの行数

#21

投稿記事 by mii » 15年前

とりあえず出来たので張ります。
お忙しい中ありがとうございます!

ちょっとフラグの状態で戸惑ってしまいました(汗
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
    FILE    *fp;            // ファイルポインタ
    int  cntOff = 0;
    int  ch;
    int  back=0;
    int start=1;
    int count = 0;
    // ファイルオープン
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    while((ch = fgetc(fp)) != EOF) {
        if (ch == '/' && back == '/') {
            cntOff = 1;
        }
        else if (ch == '*' && back == '/') {
            cntOff = 2;
        }
        else if (ch == '/' && back == '*') {
            cntOff = -1;
            count = 2;
        }
        if (cntOff == 1 && back == '\n') {
            cntOff = 0;
        }
        else if (cntOff == -1) {
            if (count == 0) {
                cntOff = 0;
            }
            else {
                count--;
            }
        }
        if(start==0 && cntOff==0)
            putchar(back);
        start=0;
        back = ch;
    }
    if(start==0 && cntOff==0)
        putchar(back);
    fclose(fp);
    return 0;
}

mii

Re:ソースコードの行数

#22

投稿記事 by mii » 15年前

nonさんたかぎさんご迷惑をお掛けしてすみません。

お忙しい中本当にありがとうございます。

non

Re:ソースコードの行数

#23

投稿記事 by non » 15年前

>ここまでで、コメントが消えると思いますが、コメントが複数行にわたったときは
>改行は消したくありません。ですから、'\n'のときは、cntOffが何であってもputcharする
>ように変更します。

まだ、ここができてませんね。
a=10; /* bbbb
cccc */b=20;

のような場合、
このままでは、
a=10;b=20;
のように1行になってしまいませんか?
あとで、総行数をカウントしなければいけないのでまずいです。

ま、すぐにできるでしょうから、次に進みましょう。
では、次に、方法3なら

○中間ファイルを書き込みようにオープンする。
○putcharをputcに書き換える。
○一度クローズした後、先に作った行数をカウントするプログラムを後ろに貼り付ける。

でうまくいくはずです。

さて、しかし方法3の目途が立ったので、方法3をせずに、(してもいいけど)方法1に
変更します。

今作ったプログラムでputcharする文字が、ファイルから入力する文字だと考えればよいので、
このputcharの所に、前作ったプログラム(No43625)のwhileの中のプログラムをコピーします。
また、最後のputcharの所にも、必要なカウント部分を入れます。
最後のputcharの所のためには仕様をはっきりさせておく必要があります。
それは、EOFのみの行は1行として数えるのか否かです。

なお、後で追加された仕様は、自分で考えてみてください。

mii

Re:ソースコードの行数

#24

投稿記事 by mii » 15年前

とりあえず方法3で作成したみたのですが、
実行ステップ数が10桁の数字になってしまいます(汗
どのようにすればよいでしょうか?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
    FILE    *fp, *wfp;
    int        space_flag = 0;
    int      cntOff = 0;
    int      ch;
    int      back=0;
    int     start=1;
    int     count = 0;
    int        lineCnt;
    int        blankLines;
    
    printf("a");/* ファイルオープン 
    abc*/ printf("b");
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    if ((wfp = fopen("out.c", "w")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    while((ch = fgetc(fp)) != EOF) {
        
        if (ch == '/' && back == '/') {
            cntOff = 1;
        }
        else if (ch == '*' && back == '/') {
            cntOff = 2;
        }
        else if (ch == '/' && back == '*') {
            cntOff = -1;
            count = 2;
        }
        if (cntOff == 1 && back == '\n') {
            cntOff = 0;
        }
        else if (cntOff == -1) {
            if (count == 0) {
                cntOff = 0;
            }
            else {
                count--;
            }
        }
        if (start == 0 && cntOff == 0) {
            putc(back, wfp);
        }
        else if (back == '\n') {
            putc(back, wfp);
        }
        start=0;
        back = ch;
    }
    if (start == 0 && cntOff == 0) {
        putc(back, wfp);
    }
    fclose(wfp);
    fclose(fp);
    if ((fp = fopen("out.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    lineCnt = 1;
    while((ch = fgetc(fp)) != EOF) {
        if (ch =='\n') {
            lineCnt++;
            if (space_flag == 0) {
                blankLines++;
            }
            space_flag = 0;
        }
        else if (!isspace(ch)) {
            space_flag = 1;
        }
    }
    printf("総ステップ数   = %d\n", lineCnt);
    printf("実行ステップ数 = %d\n", blankLines);
    fclose(fp);
    return 0;
}

non

Re:ソースコードの行数

#25

投稿記事 by non » 15年前

だいたいそういうときは、初期値を入れたか疑うものです。
入れたの?

mii

Re:ソースコードの行数

#26

投稿記事 by mii » 15年前

すいません初期化に今気づきました。。。
っとnonさんの方が先でしたか(汗
すみませんでした。

ただやはり結果がおかしくて、実行ステップ数が合いません(泣

もう少し見てみます。

non

Re:ソースコードの行数

#27

投稿記事 by non » 15年前

if (start == 0 && cntOff == 0) {
    putc(back, wfp);
}
else if (back == '\n') {
     putc(back, wfp);
}
これでも間違ってはないけど、後で方法1にするときに、putcのところに
プログラムを挿入したいから、putcを1つにまとめましょう。
if ((start == 0 && cntOff == 0) || back == '\n') {
    putc(back, wfp);
}
このようにね。

mii

Re:ソースコードの行数

#28

投稿記事 by mii » 15年前

ご指摘ありがとうございます。
訂正しておきます!

mii

Re:ソースコードの行数

#29

投稿記事 by mii » 15年前

なんとかいけました。
ありがとうございます。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
    FILE    *fp, *wfp;            // ファイルポインタ
    int      cntOff = 0;        // 0はコメントでない間
    int      ch;
    int      back=0;
    int     start=1;
    int     count = 0;
    int        lineCnt;
    int        blankLines = 0;
    int        space_flag = 0;
    printf("a");/* ファイルオープン 
    abc*/ printf("b");
    
    //int
    
    /*kokikjhj*/
    
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    if ((wfp = fopen("out.c", "w")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    while((ch = fgetc(fp)) != EOF) {
        
        if (ch == '/' && back == '/') {
            cntOff = 1;
        }
        else if (ch == '*' && back == '/') {
            cntOff = 2;
        }
        else if (ch == '/' && back == '*') {
            cntOff = -1;
            count = 2;
        }
        if (cntOff == 1 && back == '\n') {
            cntOff = 0;
        }
        else if (cntOff == -1) {
            if (count == 0) {
                cntOff = 0;
            }
            else {
                count--;
            }
        }
        if ((start == 0 && cntOff == 0) || back == '\n') {
            putc(back, wfp);
        }

        start=0;
        back = ch;
    }
    if (start == 0 && cntOff == 0) {
        putc(back, wfp);
    }
    fclose(wfp);
    fclose(fp);
    if ((fp = fopen("out.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    lineCnt = 1;
    while((ch = fgetc(fp)) != EOF) {
        if (ch =='\n') {
            lineCnt++;
            if (space_flag == 0) {
                blankLines++;
            }
            space_flag = 0;
        }
        else if (!isspace(ch)) {
            space_flag = 1;
        }
    }
    printf("総ステップ数   = %d\n", lineCnt);
    printf("実行ステップ数 = %d\n", lineCnt - blankLines);
    fclose(fp);
    return 0;
}

non

Re:ソースコードの行数

#30

投稿記事 by non » 15年前

おめでとうございます。じゃ、後はがんばって。

mii

Re:ソースコードの行数

#31

投稿記事 by mii » 15年前

頑張ってみます。
本当にありがとうございました。

mii

Re:ソースコードの行数

#32

投稿記事 by mii » 15年前

方法1にしようと思ったのですが、
put文の部分にwhileのループを入れても
上手く動きませんでした(泣

non

Re:ソースコードの行数

#33

投稿記事 by non » 15年前

おはようございます。

「うまくいかない」だけでは、原因は、わかりません。
whileはいらないですからね。whileの中だけね。
もちろん、chはbackに直してね。

mii

Re:ソースコードの行数

#34

投稿記事 by mii » 15年前

おはようございます。
とりあえず直してみました。
どこがダメなのでしょうか?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
    FILE    *fp;            // ファイルポインタ
    int      cntOff = 0;        // 0はコメントでない間
    int      ch;
    int      back=0;
    int     start=1;
    int     count = 0;
    int        lineCnt = 1;
    int        blankLines = 0;
    int        space_flag = 0;
    
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    while((ch = fgetc(fp)) != EOF) {
        
        if (ch == '/' && back == '/') {
            cntOff = 1;
        }
        else if (ch == '*' && back == '/') {
            cntOff = 2;
        }
        else if (ch == '/' && back == '*') {
            cntOff = -1;
            count = 2;
        }
        if (cntOff == 1 && back == '\n') {
            cntOff = 0;
        }
        else if (cntOff == -1) {
            if (count == 0) {
                cntOff = 0;
            }
            else {
                count--;
            }
        }
        if ((start == 0 && cntOff == 0) || back == '\n') {
            lineCnt++;
            if (space_flag == 0) {
                blankLines++;
            }
            space_flag = 0;
            if (!isspace(back)) {
                space_flag = 1;
            }
        }
        start=0;
        back = ch;
    }
    if (start == 0 && cntOff == 0) {
        lineCnt++;
        if (space_flag == 0) {
            blankLines++;
        }
        space_flag = 0;
        if (!isspace(back)) {
            space_flag = 1;
        }
    }
    fclose(fp);
    printf("総ステップ数   = %d\n", lineCnt);
    printf("実行ステップ数 = %d\n", lineCnt - blankLines);
    fclose(fp);
    return 0;
}

non

Re:ソースコードの行数

#35

投稿記事 by non » 15年前

今、実行できる状況にないからソースみてもわからない。どう、うまくいかないの?

non

Re:ソースコードの行数

#36

投稿記事 by non » 15年前

No43666ではwhileの中身は下のようだけど、上は違うじゃん。
if (ch =='\n') {
            lineCnt++;
            if (space_flag == 0) {
                blankLines++;
            }
            space_flag = 0;
        }
        else if (!isspace(ch)) {
            space_flag = 1;
        }

mii

Re:ソースコードの行数

#37

投稿記事 by mii » 15年前

とりあえず総ステップ数が40行くらいのファイルを指定したのですが、
総ステップ数が504
実行ステップが350とかになります。

non

Re:ソースコードの行数

#38

投稿記事 by non » 15年前

じゃ、やっぱり、上が原因だ。

mii

Re:ソースコードの行数

#39

投稿記事 by mii » 15年前

>No43666ではwhileの中身は下のようだけど、上は違うじゃん。
ただそうすると今度は総ステップも実行ステップも1になってしまいます(泣

ちなみに上記No43666のchをbackに直してみてもだめでした。

non

Re:ソースコードの行数

#40

投稿記事 by non » 15年前

そんなはずはない。冷静になって、よく考えてみてください。

mii

Re:ソースコードの行数

#41

投稿記事 by mii » 15年前

う~ん。調べてみたんですが分かりません(泣
どこが悪いんでしょうか?

non

Re:ソースコードの行数

#42

投稿記事 by non » 15年前

添付してください。

mii

Re:ソースコードの行数

#43

投稿記事 by mii » 15年前

よろしくお願いします。
フラグの状態と変化を理解していないから、
わからないんだと思います(泣
う~ん混乱してきました。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
    FILE    *fp;                 // ファイルポインタ
    int      cntOff = 0;        // 0はコメントでない間
    int      ch;
    int      back=0;
    int     start=1;
    int     count = 0;
    int        lineCnt = 1;
    int        blankLines = 0;
    int        space_flag = 0;
    
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    while((ch = fgetc(fp)) != EOF) {
        
        if (ch == '/' && back == '/') {
            cntOff = 1;
        }
        else if (ch == '*' && back == '/') {
            cntOff = 2;
        }
        else if (ch == '/' && back == '*') {
            cntOff = -1;
            count = 2;
        }
        if (cntOff == 1 && back == '\n') {
            cntOff = 0;
        }
        else if (cntOff == -1) {
            if (count == 0) {
                cntOff = 0;
            }
            else {
                count--;
            }
        }
        if ((start == 0 && cntOff == 0) || back == '\n') {
            if (ch =='\n') {
                lineCnt++;
                if (space_flag == 0) {
                    blankLines++;
                }
                space_flag = 0;
            }
            else if (!isspace(ch)) {
                space_flag = 1;
            }
            start=0;
            back = ch;
        }
    }
    if (start == 0 && cntOff == 0) {
            if (ch =='\n') {
                lineCnt++;
                if (space_flag == 0) {
                    blankLines++;
                }
                space_flag = 0;
            }
            else if (!isspace(ch)) {
                space_flag = 1;
            }
    }
        fclose(fp);
    printf("総ステップ数   = %d\n", lineCnt);
    printf("実行ステップ数 = %d\n", lineCnt - blankLines);
    fclose(fp);
    return 0;
}

non

Re:ソースコードの行数

#44

投稿記事 by non » 15年前

まだ、チラ見ですが、chがbackになってません。

non

Re:ソースコードの行数

#45

投稿記事 by non » 15年前

start=0;
back = ch;
はifの外です。

non

Re:ソースコードの行数

#46

投稿記事 by non » 15年前

whileから出た後の、元putcharがあった部分は、無駄が多いので整理してください。

mii

Re:ソースコードの行数

#47

投稿記事 by mii » 15年前

nonさんの通り訂正してみました。

コメント等いれてみたのですが、
間違ってる部分などがあるかもしれませんがお願いします!

non

Re:ソースコードの行数

#48

投稿記事 by non » 15年前

で、結論からいえば、うまくいったのでしょうか?

countの使用目的はNo:43645 に書いてます。

mii

Re:ソースコードの行数

#49

投稿記事 by mii » 15年前

テストは少ししかしていませんがちゃんと動いています。
nonさんありがとうございます!

ただこれに追加分を付けるとなると。。。先が思いやられます(T_T)

mii

Re:ソースコードの行数

#50

投稿記事 by mii » 15年前

度々すみません。
先ほどテストしていたんですがバグがありました。
#include <stdio.h>
/*#include <stdlib.h>*/
#include <ctype.h>
//int main(void)

/*
kome
}*/ abc

abc //kome
というファイルでテストしていたのですが、期待する結果とは違う結果
になってしまいました。どこがおかしいのでしょうか?

non

Re:ソースコードの行数

#51

投稿記事 by non » 15年前

何度もいうようですが、どのプログラムでどのように期待していたら、どう期待する結果と
違うのかがわからないと答えようがないです。
プログラムは添付ファイルのままですか?

mii

Re:ソースコードの行数

#52

投稿記事 by mii » 15年前

おはようございます。

>何度もいうようですが、どのプログラムでどのように期待していたら、どう期待する結果と
違うのかがわからないと答えようがないです。
プログラムは添付ファイルのままですか?

その通りです。問題提示だけしてしまってすみませんでした。

プログラムムは添付のままで、以下がテストファイル内容です。
とりあえずコンパイルが通るという条件でテストファイルを作成しました。
1 #include <stdio.h>
2         
3 int main(void)
4 {
5     int a;    // a
6     
7    // aだよ int b;
8    
9    /*
10    int
11    int
12    */    int b;
13    
14    /*****************************************
15    **********************/
16 }
17 #include <stdio.h>
18
19 /*#include <stdlib.h>*/
20
21 #include <ctype.h>
22
23 //int main(void)
24
25
26
27 /*
28
29 kome
30
31 }*/ double abc;
32
33
34
35 double cba; //kome
36
37 [EOF]
上記だと総ステップが37、実行ステップが10になるようにしたいのですが、
実行ステップが12になってしまいます。よろしくお願いいたします。

non

Re:ソースコードの行数

#53

投稿記事 by non » 15年前

whileから抜けた後の、putcharの代わりに挿入したプログラムに問題があります。

backに入っている文字は1文字前であることから、最後の1文字を考慮しなくてはいけません。
今回のようにEOFの1つ前の行が、空白行の時のカウントをするプログラム部分が必要ですが、
ここには書かれていません。

もう一つは、No:43654 の最後で書いたように、EOFしかない行を1行として数えるかどうかです。
もし、数えるのなら、このような場合は当然空白行としてもカウントが必要です。

なお、データに行番号がついていると、同じ条件で試せないので、不便です。

mii

Re:ソースコードの行数

#54

投稿記事 by mii » 15年前

>なお、データに行番号がついていると、同じ条件で試せないので、不便です。
わざわざつけちゃってすいません。逆に不便ですよね。消したものを張りなおします!
// 最初の文字でないかつ非コメント状態であれば
if (start == 0 && cntOff == 0) {
    if (back =='\n') {
        lineCnt++;
    }
        // この部分を追加しました
    // EOFしかない行を1行として数える
    if (space_flag == 0) {
        blankLines++;
    }
}
>今回のようにEOFの1つ前の行が、空白行の時のカウントをするプログラム部分が必要
これはどういう風に書いたらよいでしょうか?

mii

Re:ソースコードの行数

#55

投稿記事 by mii » 15年前

#include <stdio.h>

int main(void)
{
int a; // a

// aだよ int b;

/*
int
int
*/ int b;

/*****************************************
**********************/
}
#include <stdio.h>

/*#include <stdlib.h>*/

#include <ctype.h>
総数は37になります!

//int main(void)



/*

kome

}*/ double abc;



double cba; //kome

non

Re:ソースコードの行数

#56

投稿記事 by non » 15年前

whileの外の部分はこんな感じかな?チェックをあまりしてないけど。
if (start == 0) {
            if (back =='\n') {
                lineCnt++;
                blankLines++;
            }
            if (space_flag == 0)
                blankLines++;
    }
    else{
        blankLines=1;    
    }

mii

Re:ソースコードの行数

#57

投稿記事 by mii » 15年前

ありがとうございます!
whileの外部分をnonさんのソースでためした所希望通りの結果が出ました。

ちなみに3番目の仕様については#がきたらその行をカウント、
カッコだけがきたらその行をカウントする方法でよいでしょうか?

ただカッコだけとなるとどう判断すればいいのか困っています。

mii

Re:ソースコードの行数

#58

投稿記事 by mii » 15年前

とりあえず関数化してコメントを付けて見ました。

処理ステップ数 (実ステップ数のうち、プリプロセッサ行・中カッコのみの行を除いたステップ数)
を求める為にはどうすればよいでしょうか?

よろしくお願いします。

non

Re:ソースコードの行数

#59

投稿記事 by non » 15年前

後は自分で考えて欲しいのだけど・・・
じゃ、最後のヒントで。
まず、仕様の条件を絞ること。

今回は#が出てきた行数と{または}のみ現れた行数をカウントしました。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
    FILE    *fp;                // ファイルポインタ
    int        lineCnt;            // 行数
    int        sharpLines = 0;        // 空白行
    int        sharp_flag = 0;
    int        braceLines = 0;
    int        brace_flag =0;
    int        ch;
    // ファイルオープン
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    while((ch = fgetc(fp)) != EOF) {
        if (ch =='\n') {
            if (sharp_flag == 1) 
                sharpLines++;
            if (brace_flag ==1)
                braceLines++;
            sharp_flag = 0;
        }
        else if (!isspace(ch)){
            if (ch == '{' || ch == '}')
                if(brace_flag==0)
                    brace_flag=1;
            else
                brace_flag=2;
        }
        if (ch=='#') {
            sharp_flag = 1;
        }
    }
    printf("プリプロセッサ = %d\n", sharpLines);
    printf("括弧の行 = %d\n", braceLines);
    
    return 0;
}

mii

Re:ソースコードの行数

#60

投稿記事 by mii » 15年前

本当にありがとうございます!
実行してみたんですが

#include

int main(void) {

}
}
}
{

とすると括弧の数が4になって欲しいのですが2と表示されてしまいます。
どうしたらよいでしょうか?

mii

Re:ソースコードの行数

#61

投稿記事 by mii » 15年前

度々すいません。修正出来ました。
もうちょっと頑張ってみます!

non

Re:ソースコードの行数

#62

投稿記事 by non » 15年前

テストしてなかったので、抜けがありましたね。
今度は実行して確認しました。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
    FILE    *fp;                // ファイルポインタ
    int        lineCnt;            // 行数
    int        sharpLines = 0;        // 空白行
    int        sharp_flag = 0;
    int        braceLines = 0;
    int        brace_flag =0;
    int        ch;
    // ファイルオープン
    if ((fp = fopen("a.c", "r")) == NULL) {
        printf("open error\n");
        exit(EXIT_FAILURE);
    }
    while((ch = fgetc(fp)) != EOF) {
        if (ch =='\n') {
            if (sharp_flag == 1) 
                sharpLines++;
            if (brace_flag ==1)
                braceLines++;
            sharp_flag = 0;
            brace_flag=0;
        }
        else if (!isspace(ch)){
            if (ch == '{' || ch == '}'){
                if(brace_flag==0)
                    brace_flag=1;
            }
            else
                brace_flag=2;
        }
        if (ch=='#') {
            sharp_flag = 1;
        }
    }
    printf("プリプロセッサ = %d\n", sharpLines);
    printf("括弧の行 = %d\n", braceLines);
    
    return 0;
}

mii

Re:ソースコードの行数

#63

投稿記事 by mii » 15年前

ありがとうございます!
上手く組み込める用やってみます。

mii

Re:ソースコードの行数

#64

投稿記事 by mii » 15年前

う~ん。。。やはり中々上手くいきませんね(泣

nonさんに頂いたサンプルだと上手く動くのですが、
組み込んでみたら上手くカウント出来ませんでした。

なぜか括弧の数が少なく出てきます。。。

何度もすいません。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
    FILE    *fp;            // ファイルポインタ
    int      currentChar;        // 現在の文字
    int      backChar = 0;        // 1個前の文字
    int      commentFlag = 0;    // 各コメント状態を表す    
    int     countFlag = 0;        // 複数行コメントの終了判定
    int        spaceFlag = 0;        // 空白又はTABを判定
    int     startFlag = 1;        // 最初の文字か判定    
    int        lineCnt = 0;        // 総ステップ数
    int        nonRealCnt = 0;        // 実ステップ数に含めない数
    int        sharp_flag = 0;
    int        brace_flag = 0;
    int        sharpLines = 0;
    int        braceLines = 0;
    // ファイルオープン
    if ((fp = fopen("b.c", "r")) == NULL) {
    printf("open error\n");
    exit(EXIT_FAILURE);
    }
    while ((currentChar = fgetc(fp)) != EOF) {
    // 単一行コメントの開始
    if (currentChar == '/' && backChar == '/') {
            commentFlag = 1;
        }
    // 複数行コメントの開始
        else if (currentChar == '*' && backChar == '/') {
            commentFlag = 2;
        }
    // 複数行コメントの継続
        else if (currentChar == '/' && backChar == '*') {
            commentFlag = -1;
            countFlag = 2;
        }
    // 単一行コメント終了判断
        if (commentFlag == 1 && backChar == '\n') {
            commentFlag = 0;
        }
    // 複数行コメント終了判断
        else if (commentFlag == -1) {            
        // 複数行コメントが非コメント状態
            if (countFlag == 0) {
                commentFlag = 0;
            }
        // 複数行コメント継続状態
            else {
                countFlag--;
            }
        }
        // 非コメント状態又は読み取った文字の1個前が改行文字のいずれか
        if ((startFlag == 0 && commentFlag == 0) || backChar == '\n') {        
            // 1個前の文字が改行文字だった場合
            if (backChar =='\n') {
                lineCnt++;
                if (sharp_flag == 1) {
                    sharpLines++;
                }    
                if (brace_flag == 1) {
                    braceLines++;
                }
                // コメント又は空白行であれば
                if (spaceFlag == 0) {
                    nonRealCnt++;
                }
                spaceFlag = 0;
                sharp_flag = 0;
                brace_flag = 0;
            }
            // 1個前の文字が空白又はTAB文字文字以外の場合
            else if (!isspace(backChar)) {        
                if (backChar == '{' || backChar == '}') {        
                    if (brace_flag == 0) {
                        brace_flag = 1;
                    }
                }
                spaceFlag = 1;
            }
            else {
                brace_flag = 2;
            }    
            if (backChar == '#') {
                sharp_flag = 1;
            }
        }
        startFlag = 0;
        backChar = currentChar;
    }
    printf("プリプロセッサ = %d\n", sharpLines);
    printf("括弧の行 = %d\n", braceLines);
    return 0;
}

mii

Re:ソースコードの行数

#65

投稿記事 by mii » 15年前

う~ん。。。
グチャグチャになってしまって、
どうしても上手くいきません(泣

どうしたら良いのでしょうか?

non

Re:ソースコードの行数

#66

投稿記事 by non » 15年前

1つめは
>brace_flag = 2;
の場所でしょ。
2つめは、
EOFの直前の文字の処理。

mii

Re:ソースコードの行数

#67

投稿記事 by mii » 15年前

nonさんありがとうございます。

以下のテスト用ファイルを用いてテストを行っているのですが
総ステップ27
実行ステップ18
処理ステップ11
となり実行ステップ17、処理ステップ10となる予定でした。
どこがおかしいのでしょうか?

ちなみにEOFのみの場合は行に含めず、1文字以上の何か文字や、
空白があった場合は行数にカウントするということになりました(泣

これは0からカウントすることで何とかしているんですが、
EOF行だけの場合、文字が来たときに1行とするのはどうすればよいでしょうか?

質問ばかりですみません。

mii

Re:ソースコードの行数

#68

投稿記事 by mii » 15年前

>ちなみにEOFのみの場合は行に含めず、1文字以上の何か文字や、
空白があった場合は行数にカウントするということに

これはどういう風に修正すればよいでしょうか?
どうしても修正すると他の部分に影響が出たりして上手くいきません(泣

mii

Re:ソースコードの行数

#69

投稿記事 by mii » 15年前

最終行は、EOFのみの行でも、文字があって行の終わりにEOFでも正しく計算するには、
大幅な修正が必要なんでしょうか?どうすれば良いでしょうか(T_T)

ドラ

Re:ソースコードの行数

#70

投稿記事 by ドラ » 15年前

かなり手こずっておられますね・・・。

>最終行は、EOFのみの行でも、文字があって行の終わりにEOFでも正しく計算するには、
>大幅な修正が必要なんでしょうか?どうすれば良いでしょうか(T_T)
EOFがくるとwhile文を抜けますが、抜けた先でbackCharの値を見てフラグを更新した後、
フラグの状態を見て行数をカウントすれば良いのでは?
ただ、backCharを見て行数をカウントするよりcurrentCharを見て行数をカウントする方が
都合がいいような気がします。
(これまでの流れを全て追っているわけではないので見当違いかもしれませんが・・・)


それから、最終結果が自分の想定した結果と違うということを言っておられますが
途中経過のどこで想定と食い違っているか把握していますか?

ファイルから読みとった文字を1文字ずつコンソール画面に表示していき、
改行文字またはEOFが来たら、その行が何の行と判定されたかを表示していけば
問題がある部分を把握しやすくなると思います。

mii

Re:ソースコードの行数

#71

投稿記事 by mii » 15年前

おはようございます。

昨日レビューらしきものをしたんですが、//がきたら改行まで読み飛ばす。
/*がきたら*/を探してしまえばいいんじゃないかという風になってしまいました(汗

何やら混乱状態です(T_T)

>それから、最終結果が自分の想定した結果と違うということを言っておられますが
途中経過のどこで想定と食い違っているか把握していますか?

やはりここが問題です。フラグの制御を追い切れていないのが原因ですよね。

>ファイルから読みとった文字を1文字ずつコンソール画面に表示していき、
改行文字またはEOFが来たら、その行が何の行と判定されたかを表示していけば
問題がある部分を把握しやすくなると思います。

なるほど!ちょっとその方法で試してみます!

ありがとうございました。

mii

Re:ソースコードの行数

#72

投稿記事 by mii » 15年前

//がきたら改行まで読み飛ばす
/*がきたら次の*/まで読み飛ばすようにして、
コメント行、空白行を分けてカウントするようにしました。

1 int a; // コメント
2 /*
3 コメント
4 コメント
5 コメント
6 */ int a;

などと入力されていると、
1行目と6行目はコメント行に認識したくないのですが、
コメント行と認識されてしまいます。

どういう風に修正したらよいでしょうか?

non

Re:ソースコードの行数

#73

投稿記事 by non » 15年前

まだやってたのねと思って覗いたら・・・

>昨日レビューらしきものをしたんですが、//がきたら改行まで読み飛ばす。
>/*がきたら*/を探してしまえばいいんじゃないかという風になってしまいました(汗

いつのまにかアルゴリズムが変わったのね。
「なってしまいました」ってのが、よくわからないけど。チームですか?

まっ、いずれにしても、私は厭きたので、頑張ってください。
アルゴリズムも変わったし、スレッドを立て直したら、他の方のレスもあるかもね。

ドラ

Re:ソースコードの行数

#74

投稿記事 by ドラ » 15年前

nonさんが厭きておられるようなので代わりに・・・

>1行目と6行目はコメント行に認識したくないのですが、
>コメント行と認識されてしまいます。
コメントを読み飛ばしている最中に'\n'が来たら、その行はコメント行として
カウントしていることが問題です。

混乱しているなら、まず問題を整理することからはじめましょう。
1行の中にどのような項目が存在する可能性があるか考えてください。
 ・空白類文字
 ・コメント
 ・中カッコ
 ・前処理
 ・その他の文字
の5つですね。
という事は'\n'またはEOFを読み込んだときに5種類のフラグの状態を調べて
何の行なのかを判定すればいいことになりませんか?

後はどのフラグが立っているときに何の行と判定すればいいのかを
見抜く事ができればとりあえず完成しそうです。

mii

Re:ソースコードの行数

#75

投稿記事 by mii » 15年前

ドラさんありがとうございます。

そういう方法があったのですね!
思いつかず、力技で処理してしまいました。
論理的じゃないのできっとバグがあると思いますが(汗

後はEOF行だけの時の処理ですが、
これも力技しかないのかなぁと。
考えるのは難しいですね。。。(泣

mii

Re:ソースコードの行数

#76

投稿記事 by mii » 15年前

取りあえず修正した後、
以下のテストファイルを用いてテストしてみました。

<test1>
/**/#include <stdio.h>#include <stdlib.h>/* --- */int a;
#define LOKI 123
#define IKOL 123
#
void main()
{ //ask
int a,b ;/* bbb */
a=0;/* ccc */ /*
a\n
a */
/* ddd */ /* ooo
a\n
a */
a=0 ;/* eee */ /* */ /* */
//aaa
b=a ;//
b=a ; /* b */b=b;
printf( "\" " ) ;
b=1 ;
while(a!=b)
{ a=b ;
}
// printf( "%d\n",LOKI ) ;
/*/
int g;
*/
}

正しくは
コメント行 = 10
空白行 = 0
シャープ行 = 4
中カッコ行 = 3
なのですが
コメント行が9
中カッコ行が2になってしまいます。

<test2>
/**/#include <stdio.h>#include <stdlib.h>/* --- */int a;
#define LOKI 123
#define IKOL 123
#
/**/#define AA 123/***/
//#define BB 456
#define CC 789 /*
#define DD 741
*/
void main()
{ //ask
int a,b ;/* bbb */
a=0;/* ccc */ /*
a\n
a */
/* ddd */ /* ooo
a\n
a */
a=0 ;/* eee */ /* */ /* */
//aaa
b=a ;//
b=a ; /* b */b=b;
printf( "\" " ) ;
b=1 ;
while(a!=b)
{ a=b ;
}
// printf( "%d\n",LOKI ) ;
/*/
int g;
*/

}

int main2()
{ int j;/*
*/ int i;/***//**//*
int bb;
*/
// int cc;
for (i = 9; i< 10; i++) {
/**/{/**/ printf("%d\n", i);
}} // aaaa
/**/}}

こちらは正しくは
コメント行 = 16
空白行 = 2
シャープ行 = 6
中カッコ行 = 5
なのですが
中カッコ行が2になってしまいます。
こちらはなぜかコメントは正常でした。

どこに問題があるか教えていただけないでしょうか?

またファイル内容がEOFのみの1行だけの場合
上手く処理出来ません(泣
最初の1文字を上手く取れてないんでしょうか?

お力添えよろしくお願いいたします。

Mist

Re:ソースコードの行数

#77

投稿記事 by Mist » 15年前

途中経過を表示させて確認していますか?
printfデバッグすれば、どの時点で自分の思い描くとおりに動いていないかすぐにわかると思いますよ。

http://funini.com/kei/c/debug.shtml

ドラ

Re:ソースコードの行数

#78

投稿記事 by ドラ » 15年前

>backChar = fgetc(fp);
これはまずいのでは?
backCharはコメントの開始を判定するのに使っているだけなので'/'以外
の文字でもセットしておいて下さい。


>後はEOF行だけの時の処理ですが、 これも力技しかないのかなぁと。
EOFを読み込んだときどのフラグも立っていなかったらEOFだけの行と判定するとか・・
EOFを読み込んだときのbackCharが'\n'ならEOFだけの行と判定するとか・・
(これをやるならbackCharの初期値は'\n'が適当ですね)


それから'#'が来たら'\n'が来るまで読み飛ばさないといけないのでは?


ソースコードをざっと見てみましたが、できているところとできていないところが
混ざり合っているように見えました。
今のソースは捨てて、最初から作りなおしてみてはどうでしょうか?
その時に一気に作りたいものの仕様を満たすものを作ろうとするのではなく、
まずは空白のみの行数とそれ以外の行数を正確にカウントできるものを目指して下さい。
(合計すれば総行数も出てきますね)

このときに、前にも言った
「ファイルから読みとった文字を1文字ずつコンソール画面に表示していき、
 改行文字またはEOFが来たら、その行が何の行と判定されたかを表示していけば 」
を実践して下さい。
これがMistさんのおっしゃられているprintfデバッグです。
途中経過ではバグっているのに最終結果だけは自分の想定通りというようなケースも
考えられますので・・・

ここまでの事がきちんと出来るようになったら、今度は空白のみの行数、コメントのみの行数、
それ以外の行数を正確にカウントできるように仕様を拡張していきましょう。
このような事を実践することで自分の書いたソースコードの中でできている部分と
問題がありそうな部分を切り離して考える事ができるようになります。
miiさんの質問を見ていると、これができていません。

mii

Re:ソースコードの行数

#79

投稿記事 by mii » 15年前

Mistさんドラさんありがとうございます。

提出日が月曜なので間に合うかどうかわかりませんが、
新しく作ってみようと思います!

わからなくなったらまた質問すると思うのでよろしくお願いします。

non

Re:ソースコードの行数

#80

投稿記事 by non » 15年前

提出期限が近そうなので、少しお手伝い。
ただし、最初の考えかたNo44014の添付ファイルを使ってです。
int Cstep(const char *filePath, FILE *fp)
{
    int      currentChar;        // 現在の文字
    int      backChar = 0;        // 1個前の文字
    int      commentFlag = 0;    // 各コメント状態を表す        (0の場合非コメント状態)
    int     countFlag = 0;        // 複数行コメントの終了判定    (0の場合非コメント状態)
    int        spaceFlag = 0;        // 空白又はTABを判定        (0の場合空白又はTAB状態)
    int     startFlag = 1;        // 最初の文字か判定            (0の場合2個目以降の文字)
    int        lineCnt = 0;        // 総ステップ数
    int        nonRealCnt = 0;        // 実ステップ数に含めない数
    int        sharp_flag = 0;
    int        brace_flag = 0;
    int        sharpLines = 0;
    int        braceLines = 0;
    int        cF=0;
    
    while ((currentChar = fgetc(fp)) != EOF) {
        
        // 単一行コメントの開始
        if (currentChar == '/' && backChar == '/') {
            commentFlag = 1;
        }
        // 複数行コメントの開始
        else if (currentChar == '*' && backChar == '/') {
            commentFlag = 2;
            cF=2;
        }
        // 複数行コメントの継続
        else if (currentChar == '/' && backChar == '*' && cF==0) {
            commentFlag = -1;
            countFlag = 2;
        }
        if(cF>0) cF--;
        // 単一行コメント終了判断
        if (commentFlag == 1 && backChar == '\n') {
            commentFlag = 0;
        }
        // 複数行コメント終了判断
        else if (commentFlag == -1) {
            
            // 複数行コメントが非コメント状態
            if (countFlag == 0) {
                commentFlag = 0;
            }
            // 複数行コメント継続状態
            else {
                countFlag--;
            }
        }

        // 非コメント状態又は読み取った文字の1個前が改行文字のいずれか
        if ((startFlag == 0 && commentFlag == 0) || backChar == '\n') {
            
            // 1個前の文字が改行文字だった場合
            if (backChar =='\n') {
                lineCnt++;
                
                if (sharp_flag == 1) {
                    sharpLines++;
                }
                
                if (brace_flag == 1) {
                    braceLines++;
                }
                // コメント又は空白行であれば
                if (spaceFlag == 0) {
                    nonRealCnt++;
                }
                
                spaceFlag = 0;
                sharp_flag = 0;
                brace_flag = 0;
            }
            // 1個前の文字が空白又はTAB文字文字以外の場合
            else if (!isspace(backChar)) {
                
                // 1個前の文字が括弧の場合
                if (backChar == '{' || backChar == '}') {
                    
                    if (brace_flag == 0) {
                        brace_flag = 1;
                    }
                }
                else {
                    brace_flag = 2;
                }
                
                spaceFlag = 1;
            }
            
            if (backChar == '#') {
                sharp_flag = 1;
            }
        }
        
        startFlag = 0;
        backChar = currentChar;
    }
    Print(filePath, lineCnt, nonRealCnt, sharpLines, braceLines);    
    // 最初の文字でなく
    if (startFlag == 0) {
        // 1個前の文字が改行文字の場合
//        if (backChar =='\n') {
            lineCnt++;
            //nonRealCnt++;
//    }    

        // 空白又はTAB状態の場合
        if (spaceFlag == 0) {
            nonRealCnt++;
        }
        
        if (sharp_flag == 1) {
            sharpLines++;
        }
        
        if (brace_flag == 1) {
            braceLines++;
        }
    }
    
    // 表示
    Print(filePath, lineCnt, nonRealCnt, sharpLines, braceLines);
    
    return 0;
}
あの段階で問題になったのはEOFのみの行をカウントしないようにするということでした。
上の赤いコメントにしたところが、その処理です。これくらいは、自分で考えられると思い
わざと、放っておきました。
次に問題になったのは、No44384のファイルでコメント行の数があわないという件です。
これは、
/*/
int g;
*/
の場合が、チェックからもれていました。
/*の*が次の*/とダブって認識したのが原因です。
そこで、カウンタを設けて、1文字読み飛ばすようにしました。
これが、黄色文字の部分です。

なんで、最初の方法で最後まで頑張らないんだろ?
fgetcが複数の箇所に出てくるのは、好きじゃないなぁ。

Mist

Re:ソースコードの行数

#81

投稿記事 by Mist » 15年前

> なんで、最初の方法で最後まで頑張らないんだろ?
ここまでの流れを見ての私の感想。

デバッグが出来ていない(処理の途中経過を追えていない)ので微細な間違いが修正できない。

やり方自体に問題があるんだ!(この方法では無理)という結論になる。

違うやり方で解決しようとする。

大幅に修正する。

正しかったところまで動かなくなる。

気づいた範囲で修正してある程度までは動くけど、微細な間違いを修正できないから終わらない。

以下、エンドレス

mii

Re:ソースコードの行数

#82

投稿記事 by mii » 15年前

nonさんありがとうございます。

どうしてもわからないのですが、
else if (currentChar == '/' && backChar == '*' && cF==0) {
    commentFlag = -1;
    countFlag = 2;
}
のカウントフラグ = 2の部分ですが、どうして2にするのでしょう?
過去レス見たんですが、あの時はputcharで出力したくないとのことでしたが、
どういうことなんでしょうか?

上手く説明できずに困っています(泣

non

Re:ソースコードの行数

#83

投稿記事 by non » 15年前

No43645の再掲です。

> では次に、/*~*/のコメントです。
> 基本的な考え方は//と同じです・
> /*のとき cntOff = 2 にしましょう。
>
> */のとき cntOff=0 にすればよさそうですが、まだ*/の2文字を
> 出力したくないので、int count を用意して
> cntOff=-1にしておいて、
> count=2にします。
>
> cntOff=-1のとき
> count==0になったらcntOff=0にします。
> そうでなければ、countを減らします。

意味がわからないのなら、countFlag = 0;
でどう動作するのか試してみればいい。

mii

Re:ソースコードの行数

#84

投稿記事 by mii » 15年前

>意味がわからないのなら、countFlag = 0;
でどう動作するのか試してみればいい。

そうですよね(汗
なぜ気付かなかったんだろう。。。orz
早速やってみます!
ありがとうございます。

mii

Re:ソースコードの行数

#85

投稿記事 by mii » 15年前

後は1文字だけでEOF行だけの場合の処理になりました。
a[EOF]

この場合必ずspaceFlagが0なので、この行が空白行扱いになってしまいます。
これを回避するにはどうすればいいでしょうか?

文字の長さを取得して1行かつ1文字だったらという条件でやろうとしたのですが、
1文字が2バイト文字だと2文字扱いになるのでどうしようかと思いまして。

mii

Re:ソースコードの行数

#86

投稿記事 by mii » 15年前

"コンパイルが通る"という仕様を忘れておりました。
ということなので1文字等に関しては無視してOKとのことでした。

管理人さん、nonさん、たかぎさん、ドラさん、Mistさん
本当にありがとうございました。

特にnonさんにはかなりご迷惑をおかけして申し訳ありませんでした。

ここで質問者の回答が出来るくらいにCを勉強したいと思います。

また来るかもしれませんが、その際はよろしくお願いします。

閉鎖

“C言語何でも質問掲示板” へ戻る