我的程序(2):c源码统计器

我的程序(2):c源码统计器

这是大二时数据结构的课程设计,要求用vc做一个有用户界面的程序.因为当时还不会用vc,所以在去年寒假用c写了一个没有界面的源码统计器,就算是课程设计的内核吧.

期间又该了多次,添加一些功能,增强安全性,对代码进行优化等,总共又5个版本.贴出来几个有代表性的,希望大家指正.

0.0  :在键盘上输入程序,然后程序返回结果.

                      /*统计c中代码行和注释行的数量*/

#include<stdio.h>

 

void recomment(int c,int *pzhushi,int *phangshu,int *flagzhushi,int *flagzhw);

void in_comment(int *pzhushi,int *phangshu, int *flagzhushi,int *flagzhw);

void echo_quote(int c);

 

main()

{

int c;

    int nzhushi=0, nhangshu=0;   /* 记录注释和总行数*/

    int *pzhushi=&nzhushi;

    int *phangshu=&nhangshu;

    int *flagzhushi, *flagzhw;  /*标志:是否在注释或代码中*/

    *flagzhushi=0,  *flagzhw=0;

 

 

    while( (c=getchar())!=EOF )

        recomment(c,pzhushi,phangshu,flagzhushi,flagzhw);

 

    printf("%d,%d/n",*pzhushi,*phangshu);

    getch();

    return 0;

}   /*主函数完成*/

           

 

 

void recomment(int c,int *pzhushi,int *phangshu,int *flagzhushi,int *flagzhw)

{

 

     int d;

    if (c == '/'){

        if ( (d=getchar()) =='*' )

            in_comment(pzhushi,phangshu,flagzhushi,flagzhw);/* 进入注释处理函数*/

        else if ( d == '/' )

            recomment(d,pzhushi,phangshu,flagzhushi,flagzhw); /*递归*/

    }

 

    else if ( c == '/'' || c == '"' )

        echo_quote(c);                  /* 在引号内的注释不算*/

    else if ( c == '/n'){               /* 对回车的处理(考虑了各种情况)*/

        if(*flagzhushi == 1 )           /*如果此行有注释*/

            ++ (*pzhushi);

        if ( *flagzhw==1 )

            ++ (*phangshu);

        *flagzhw=*flagzhushi=0;

    }else if ( *flagzhw == 0 && c !=' ' )

        *flagzhw=1;

}   /*完成*/

            

 

void in_comment(int *pzhushi,int *phangshu, int *flagzhushi,int *flagzhw)

{

 

    int c,d;

 

    c=getchar();

    d=getchar();

    while ( c != '*' || d != '/' ){

        if ( c == '/n' ){

            ++ (*pzhushi);

            if ( *flagzhw == 1 )

                ++ (*phangshu);

        }

        c=d;

        d=getchar();

    }

    *flagzhushi=1;

}  /* 完成*/

 

 

 

void echo_quote(int c) 

{

    int d;

    while ( (d=getchar()) !=c )

        if ( d=='//')

            getchar();              /*忽略转义字符*/

}    /*完成*/

 

1.0    主要对0.0版本中复杂的函数参数进行了修改,用一个结构指针解决问题.(谢谢csdn上面的朋友的指点)

/*统计c中代码行和注释行的数量*/

#include<stdio.h>

 

 struct fun{

     int ncomment;

     int ncode;

     int flagcomment;

     int flagcode;

 }a;

 struct fun *p=&a;

 

 

 

 

void recomment(int c,struct fun *p);

void in_comment(struct fun *p);

void echo_quote(int c);

 

main()

{

 

 

    int c;

 

 

    while( (c=getchar())!=EOF )

        recomment(c,p);

 

    printf("%d,%d/n",p->ncomment,p->ncode);

     getch();

    return 0;

}   /*主函数完成*/

           

 

 

 

 

    

void recomment(int c,struct fun *p)

{

 

     int d;

    if (c == '/'){

        if ( (d=getchar()) =='*' )

            in_comment(p);/* 进入注释处理函数*/

        else if ( d == '/' )

            recomment(d,p); /*递归*/

    }

 

    else if ( c == '/'' || c == '"' )

        echo_quote(c);                  /* 在引号内的注释不算*/

    else if ( c == '/n'){               /* 对回车的处理(考虑了各种情况)*/

        if(p->flagcomment == 1 )           /*此行有注释*/

            ++ (p->ncomment);

        if ( p->flagcode==1 )

            ++ (p->ncode);

        p->flagcode=p->flagcomment=0;

    }else if ( p->flagcode == 0 && c !=' ' )

       p->flagcode=1;

}   /*完成*/

           

 

void in_comment(struct fun *p)

{

 

    int c,d;

 

    c=getchar();

    d=getchar();

    while ( c != '*' || d != '/' ){

        if ( c == '/n' ){

            ++ (p->ncomment);

            if ( p->flagcode == 1 )

                ++ (p->ncode);

        }

        c=d;

        d=getchar();

    }

   p->flagcomment=1;

}  /* 完成*/

 

 

 

void echo_quote(int c) 

{

    int d;

    while ( (d=getchar()) !=c )

        if ( d=='//')

            getchar();              /*忽略转义字符*/

}    /*完成*/

 

3.0版本    不再由键盘输入程序,输入程序的路径即可.(但反斜杠问题没有解决0

/*统计c中代码行和注释行的数量*/

#include<stdio.h>

#include<stdlib.h>

 

 struct fun{

     int ncomment;

     int ncode;

     int flagcomment;

     int flagcode;

      FILE *pf;

 }a = {0,0,0,0,NULL};

 struct fun *p=&a;

 

 

 

 

void recomment(int c,struct fun *p);

void in_comment(struct fun *p);

void echo_quote(int c,struct fun *p);

 

main()

{

    int c;

     char s[50];

    

    printf("input the path of the file(注意;当输入反斜杠时,请连续输入两个)这个问题将在下一版中解决/n");

     scanf("%s",s);

   

    p->pf = fopen(s,"r");

    if( p->pf == NULL ){

        printf("open fail!/n");

        exit(0);

    }

 

    while( ( c=fgetc(p->pf) ) != EOF )

        recomment(c,p);

 

    printf("%d,%d/n",p->ncomment,p->ncode);

    fclose(p->pf);

    return 0;

}   /*主函数完成*/

           

 

 

 

 

void recomment(int c,struct fun *p)

{

 

     int d;

    if (c == '/'){

        if ( (d=fgetc(p->pf)) =='*' )

            in_comment(p);/* 进入注释处理函数*/

        else if ( d == '/' )

            recomment(d,p); /*递归*/

    }

 

    else if ( c == '/'' || c == '"' )

        echo_quote(c,p);                  /* 在引号内的注释不算*/

    else if ( c == '/n'){               /* 对回车的处理(考虑了各种情况)*/

        if(p->flagcomment == 1 )           /*此行有注释*/

            ++ (p->ncomment);

        if ( p->flagcode==1 )

            ++ (p->ncode);

        p->flagcode=p->flagcomment=0;

    }else if ( p->flagcode == 0 && c !=' ' )

       p->flagcode=1;

}   /*完成*/

           

 

void in_comment(struct fun *p)

{

 

    int c,d;

 

    c=fgetc(p->pf);

    d=fgetc(p->pf);

    while ( c != '*' || d != '/' ){

        if ( c == '/n' ){

            ++ (p->ncomment);

            if ( p->flagcode == 1 )

                ++ (p->ncode);

        }

        c=d;

        d=fgetc(p->pf);

    }

   p->flagcomment=1;

}  /* 完成*/

 

 

 

void echo_quote(int c,struct fun *p) 

 

{

    int d;

    while ( (d=fgetc(p->pf)) !=c )

        if ( d=='//')

            fgetc(p->pf);              /*忽略转义字符*/

}    /*完成*/

 

4.0版本 (最终版本)  可以直接输入程序的路径

/*统计c中代码行(不包括空白行)和注释行的数量*/

#include<stdio.h>

#include<stdlib.h>

 

 struct fun{

     int ncomment;

     int ncode;

     int flagcomment;

     int flagcode;

      FILE *pf;

 }a = {0,0,0,0,NULL};

 struct fun *p=&a;

 

 

void recomment(int c,struct fun *p);

void in_comment(struct fun *p);

void echo_quote(int c,struct fun *p);

char * change(char *ps,char *pt);      /*处理路径中的反斜杠问题。因为在字符串中要用//表示/ */

 

 

main()

{

    int c;

     char s[50];

     char t[100];

     char *ps = s;

     char *pt = t;

 

     printf("input the path of the file/n");

     scanf("%s",s);

 

    p->pf = fopen( change(ps,pt),"r" );     /*打开文件*/

    if( p->pf == NULL ){                   /*输入的文件路径不对或文件不存在*/

        printf("open fail!/n");

        exit(0);

    }                                   

    while( ( c = fgetc(p->pf) ) != EOF )

        recomment(c,p);

 

    printf("the commend lines are %d/n,the all code lines(not include black lines) are %d/n",p->ncomment,p->ncode);

    fclose(p->pf);                      /*关闭文件*/

    return 0;                                

}   /*主函数完成*/

           

 

 

 

 

void recomment(int c,struct fun *p)

{

 

     int d;

    if (c == '/'){

        if ( (d = fgetc(p->pf)) =='*' )

            in_comment(p);/* 进入注释处理函数*/

        else if ( d == '/' )

            recomment(d,p); /*递归*/

    }

 

    else if ( c == '/'' || c == '"' )

        echo_quote(c,p);                  /* 在引号内的注释不算*/

    else if ( c == '/n'){               /* 对回车的处理(考虑了各种情况)*/

        if(p->flagcomment == 1 )           /*如果此行有注释*/

            ++ (p->ncomment);

        if ( p->flagcode == 1 )            /*如果此行有代码*/

            ++ (p->ncode);

        p->flagcode = p->flagcomment = 0;     /*把标志复位*/

    }else if ( p->flagcode == 0 && c != ' ' )

       p->flagcode = 1;

}   /*完成*/

           

 

void in_comment(struct fun *p)      /*寻找注释结束的地方*/

{

 

    int c,d;

 

    c = fgetc(p->pf);

    d = fgetc(p->pf);

    while ( c != '*' || d != '/' ){

        if ( c == '/n' ){

            ++ (p->ncomment);

            if ( p->flagcode == 1 )

                ++ (p->ncode);

        }

        c = d;

        d = fgetc(p->pf);

    }

   p->flagcomment = 1;

}  /* 完成*/

 

 

 

void echo_quote(int c,struct fun *p) 

 

{

    int d;

    while ( (d = fgetc(p->pf)) !=c )

        if ( d == '//')

            fgetc(p->pf);              /*忽略转义字符*/

}    /*完成*/

 

 

char * change(char *ps,char *pt)     /*处理反斜杠的问题*/

{

     char *p = pt;

     char c;

 

     while( (c = *pt++ = *ps++) != '/0' )

         if( c == '//' )

              *pt = '//';

     return p;

}

 

        

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
  岁月如梭,光阴似箭,想不到离上次1.0版推出已有1年多时间^-^。在《源码统计》推出的这一年内,许多朋友给我来信,指出其中的不足,并有许多很好的建议和鼓励,特别要感谢如下几位:Johnson Jiang、zhangxiao、jp.xie、佟晓艺、徐雷、xwing、司徒达擎、ltzhou、Hunter、birdie。   由于过去的一年多时间内工作很忙,而且我目前从事的已不再是软件开发类的工作,因此一直无暇更新。今年春节假期终于得到几天空闲,能够将自己以往的思路重新整理一下,对《源码统计》做一些更新工作。由于更新不大,因此只升级为1.1版。 主要更新的地方有: 1、 原版本统计如下代码时出错 /*……*/……/*…… 由于我原先没考虑到同一行内有两个地方注释,并且从该行开始进入注释语句(/*)。还有如下语句也统计错误: /*/ 1 //*/ 可能是对类似于/*/的情况处理不当。如下语句统计也有问题 CString str = "abc\ //de"; 因为未考虑到字符串换行的情况。 另外,1.0版对rc文件统计也不正确。 我对统计算法进行了彻底改写,以上错误均已更正。 2、 增加了"设置"按钮,使用户可以自己设置统计方法。就是当代码和注释语句处于同一行时,作何处理。1.0版本是作为代码行计数,但有网友反映有时需要分开计数。因此新版本增加了这项功能,用户可以根据需要自己设置成: ①只作为代码行处理; ②代码行和注释行各增加一行 ③只作为注释行处理; 按第一种方式和第三种方式统计,代码行+注释行+空白行一定等于总行数,而第二种方式统计代码行+注释行+空白行大于总行数,两者之差就是既有代码又有注释符的行数。《源码统计》缺省设置为第二种统计方法。 "设置"对话框中用户还可以设置日志文件的路径,这个文件我主要是用来记录统计中可能出现的错误。目前能记录cpp文件中字符串换行但没有用\结尾的问题。 3、 增加了将统计结果保存为Excel文件的功能。 4、 增加了动态图标。 5、 其他还做了一些小改动,不再一一说明。 新软件的界面为: 1.1版的《源码统计》也如原版本一样,源代码完全开放。若你需要,可来信索取,我的Email是:xiaogi@sohu.com。你也可以到我的个人主页下载:http://xiaogi.nease.net。 软件介绍:   在工作中,我们经常碰到客户要求我们告之所写程序的行数,包括代码行、注释行和空白行等。这一软件就是为这一目的编写的。最先是用于对我自己写的C/C++,VC++程序进行行数统计。它可以准确快速地统计出源代码中的各种行数。后来经过不断改进,增加了对VB, Java, ASP, Perl和Shell等程序的源代码的统计,使得软件的应用范围更加广泛。网络上也有不少类似统计行数的软件,但到目前为止,我发现“源码统计1.0版”统计速度是最快的,而且相比较发现更加准确,考虑到了源代码中可能出现的许多特殊情况。 软件优点: 1、 准确无误。这当然是任何一款源代码统计工具所必需具备的功能。为此,我自建了一个测试用的cpp文件(test.cpp),在其中我设计了多个遵循c++的注释方式,但又很容易导致统计错误的"陷阱"。虽然有些注释语句看起来有点奇怪,但的确合理并且真实存在。统计该测试文件时即使出现1行的统计误差也是不允许的,否则在统计某个恰好用该种方式注释的程序时误差就可能很大。经测试,“源码统计1.0版”能准确无误地统计出test.cpp的各种代码行数。 2、 更加快速。由于算法选取和文件处理得当,“源码统计1.0版”的统计速度相当迅速。 3、 界面友好,易于上手。"源码统计1.0版"界面说明清楚,相信任何人都能轻松上手。本软件无需安装,解压缩后可直接运行。 4、 功能丰富,智能统计。本软件可以统计多种源码,包括C/C+、VC++、VB、Java、ASP、Perl、Shell和TXT文件。可以将统计结果汇总保存为文本文件或csv文件,其中csv文件可被绝大部分统计软件识别(包括微软Office系列的Excel),方便今后进一步整理统计源码。“源码统计1.0版”还可以根据用户输入的文件扩展名自动调用相应的统计方法。 5、 源代码公开,方便用户根据自己的需要进行修改,添加对特殊文件的统计。 添加方法概述如下:假设你要添加对扩展名为"*.my"的文件统计。首先,在CountingDlg.h中定义宏: #define TYPE_MY 18 然后在CCountingDlg::OnInitDialog()中添加该类型到m_structExtention结构体: m_structExtention.arrayTy
1.1版更新介绍   岁月如梭,光阴似箭,想不到离上次1.0版推出已有1年多时间^-^。在《源码统计》推出的这一年内,许多朋友给我来信,指出其中的不足,并有许多很好的建议和鼓励,特别要感谢如下几位:Johnson Jiang、zhangxiao、jp.xie、佟晓艺、徐雷、xwing、司徒达擎、ltzhou、Hunter、birdie。   由于过去的一年多时间内工作很忙,而且我目前从事的已不再是软件开发类的工作,因此一直无暇更新。今年春节假期终于得到几天空闲,能够将自己以往的思路重新整理一下,对《源码统计》做一些更新工作。由于更新不大,因此只升级为1.1版。 主要更新的地方有: 1、 原版本统计如下代码时出错 /*……*/……/*…… 由于我原先没考虑到同一行内有两个地方注释,并且从该行开始进入注释语句(/*)。还有如下语句也统计错误: /*/ 1 //*/ 可能是对类似于/*/的情况处理不当。如下语句统计也有问题 CString str = ";;;;;;;abc//de";;;;;;;;;;;;;;; 因为未考虑到字符串换行的情况。 另外,1.0版对rc文件统计也不正确。 我对统计算法进行了彻底改写,以上错误均已更正。 2、 增加了";;;;;;;设置";;;;;;;按钮,使用户可以自己设置统计方法。就是当代码和注释语句处于同一行时,作何处理。1.0版本是作为代码行计数,但有网友反映有时需要分开计数。因此新版本增加了这项功能,用户可以根据需要自己设置成: ①只作为代码行处理; ②代码行和注释行各增加一行 ③只作为注释行处理; 按第一种方式和第三种方式统计,代码行+注释行+空白行一定等于总行数,而第二种方式统计代码行+注释行+空白行大于总行数,两者之差就是既有代码又有注释符的行数。《源码统计》缺省设置为第二种统计方法。 ";;;;;;;设置";;;;;;;对话框中用户还可以设置日志文件的路径,这个文件我主要是用来记录统计中可能出现的错误。目前能记录cpp文件中字符串换行但没有用结尾的问题。 3、 增加了将统计结果保存为Excel文件的功能。 4、 增加了动态图标。 5、 其他还做了一些小改动,不再一一说明。 1.1版的《源码统计》也如原版本一样,源代码完全开放。若你需要,可来信索取,我的Email是:xiaogi@sohu.com。你也可以到我的个人主页下载:http://xiaogi.nease.net。 软件介绍:   在工作中,我们经常碰到客户要求我们告之所写程序的行数,包括代码行、注释行和空白行等。这一软件就是为这一目的编写的。最先是用于对我自己写的C/C++,VC++程序进行行数统计。它可以准确快速地统计出源代码中的各种行数。后来经过不断改进,增加了对VB, Java, ASP,JSP和SQL等程序的源代码的统计,使得软件的应用范围更加广泛。网络上也有不少类似统计行数的软件,但到目前为止,我发现“源码统计1.1版”统计速度是最快的,而且相比较发现更加准确,考虑到了源代码中可能出现的许多特殊情况。 软件优点: 1、 准确无误。这当然是任何一款源代码统计工具所必需具备的功能。为此,我自建了一个测试用的cpp文件(test.cpp),在其中我设计了多个遵循c++的注释方式,但又很容易导致统计错误的";;;;;;;陷阱";;;;;;;。虽然有些注释语句看起来有点奇怪,但的确合理并且真实存在。统计该测试文件时即使出现1行的统计误差也是不允许的,否则在统计某个恰好用该种方式注释的程序时误差就可能很大。经测试,“源码统计1.1版”能准确无误地统计出test.cpp的各种代码行数。 2、 更加快速。由于算法选取和文件处理得当,“源码统计1.1版”的统计速度相当迅速。 3、 界面友好,易于上手。";;;;;;;源码统计1.1版";;;;;;;界面说明清楚,相信任何人都能轻松上手。本软件无需安装,解压缩后可直接运行。 4、 功能丰富,智能统计。本软件可以统计多种源码,包括C/C+、VC++、VB、Java、ASP、JSP、SQL和TXT文件。可以将统计结果汇总保存为文本文件或csv文件,其中csv文件可被绝大部分统计软件识别(包括微软Office系列的Excel),方便今后进一步整理统计源码。“源码统计1.1版”还可以根据用户输入的文件扩展名自动调用相应的统计方法。 5、 源代码公开,方便用户根据自己的需要进行修改,添加对特殊文件的统计。 添加方法概述如下:假设你要添加对扩展名为";;;;;;;*.my";;;;;;;的文件统计。首先,在CountingDlg.h中定义宏: #define TYPE_MY 16 然后在CCountingDlg::OnInitDialog()中添加该类型到m_structExtention结构体: m_structExtention.arrayType.Add(";;;;;;;my";;;;;;;);;;;;;;; m_structExtention.nType[0] = TYPE_MY;;;;;;;; 再在IsSearchingFor(CString strFileName)中添加判断,使得当strFileName为my类型时返回TRUE。 在类CCountingDlg中添加函数GetMyFileLines(),具体统计算法请在该函数内自己实现。 最后在CountThread线程中加入判断,如果文件类型为TYPE_MY,则调用函数GetMyFileLines ( )进行统计。 具体操作可参考源代码相应的处理。 6、 软件所使用的资源绝大部分位于资源文件中,便于用户更改其语言版本以用在其它语言的操作系统上。(这也是本软件下一版本要追加的一个功能:自动识别操作系统语言并载入相应的资源包) 使用方法: ◆ 在“文件名或文件类型”组合框中输入你需要进行统计的文件类型(如:*.cpp;;;;;;;;*.c;;;;;;;;*.h)。扩展名之间用;;;;;;;;,:分隔,;;;;;;;;,:前后有空格亦无妨,软件会自动忽略。你也可以直接输入需要统计的文件名(如:counting.cpp;;;;;;;; setting.c;;;;;;;; resource.h)。同样的,文件名之间也用;;;;;;;;,:分隔。点击下拉框可以选择软件缺省为你提供的几种文件类型,点击右边的按钮可以手动指定需要进行统计的文件(可多选,并且软件自动将选中文件的所在目录放入";;;;;;;搜索文件夹";;;;;;;组合框中)。 ◆ 在“搜索文件夹”组合框中输入你需要进行统计的文件所在的文件夹(如: d:study),点击下拉框可以选择近几次进行统计的文件夹。如果你手动输入的文件夹不在下拉框中,软件在统计开始后自动将该文件夹加入。点击右边的按钮可以选择文件夹。 ◆ 你可以选择统计时是否也需要统计子文件夹中的相关文件。 ◆ 点击";;;;;;;统计";;;;;;;按钮开始,再次点击该按钮停止统计。 ◆ 若你需要保存统计结果,请点击";;;;;;;保存";;;;;;;按钮。你可以选择以文本文件、Excel文件或csv文件三种格式保存。其中csv文件可被几乎所有的统计软件识别,包括微软Office系列的Excel。 ◆ 在列表控件中双击文件名可打开该文件。 ◆ 软件可稳定地运行于MS Windows系列操作系统上。 作者声明:   本软件为自由软件,源代码完全公开。你可以来信索要并不受限制地利用,但务请保留作者的版权信息。若你觉得本软件对你有帮助或你需要将其中部分的代码用到自己的软件中,请给作者来信告知。如果你对本软件有好的建议或bug发现,也请来信告知。本软件将不断更新升级,最新版本请到我的个人主页下载。 我的Email:xiaogi@sohu.com 个人主页:http://xiaogi.nease.net
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值