首页 > 代码库 > C++统计代码注释行数 & 有效代码行数 & 代码注释公共行 & 函数个数

C++统计代码注释行数 & 有效代码行数 & 代码注释公共行 & 函数个数

问题来源,在14年的暑假的一次小项目当中遇到了一个这样的问题,要求统计C++代码的注释行数,有效代码行数,代码注释公共行数,以及函数个数。

下面稍微解释一下问题,

1)注释行数:指有注释的行,包括有代码和注释的公共行(如:3,4,15,22...)

2)有效代码行:指有代码的行,包括有代码和注释的公共行(如:1,4,11,15,25....)

3)代码注释公共行:指又有代码又有注释的行(如:4,15...)

4)函数个数:这个不用说明了吧。

以下为注释情况展示代码:

 1 #include <stdio.h> 2  3 //follow is a common line 4 void swap(char *p/* = NULL */) 5 { 6     printf("this is a function /*is not comments*/"); 7 } 8  9 int main(void)10 {11     int a = 10;12     int b;13     char *p = NULL;14 15     swap(p);  //common line16     if (10 == a)17     {18         printf("is not function;//is not comments");19     }20     //pure comments/*no use*/21 22     /*a = 5;23     printf("not use\n");*/24 25     b = 3;/*i‘m a comment*/ a = 5; /*comments line26     pure //comments line;"*/......"look there*/27     printf("test \" escape char");28     //and the follow,maybe affect the count of function29     if (*p == {)30     {31         printf("the ‘{‘ is a question\n");32     }33     //34 35     return 0;36 }

上面的这个代码片段,已经基本上展示了各种注释可能出现的情况,接着我们来分析一下注释出现的位置:

一、“//”双斜杠注释

1)可能出现在行头部,如:第3行;

2)可能出现在行末尾,如:第15行;

注意:第18行,第26行。第18行中,//位于双引号中,注释失效;第26行中,//位于/**/注释中,//失效。

二、“/**/”斜杠星注释

1)可能出现在函数参数里,如:第4行;

2)可能注释一个段落,如:22,23行;

3)也可能出现在代码中部,如25,26行那样的复杂注释;

注意:第20行,第26行。第20行,/**/位于//注释中,失效。第26行,有一个*/位于“”中,*/失效。

好了,位置分析完毕,下面分析一下如何设计算法:

三、具体算法设计思路

1)解决文件读取

这里我们用c++文件读取,每次读取一行,将读取结果放到string变量里面,这样string变量尾部自动为‘\0‘。我们用于判断行尾部。

2)双引号问题

由于双引号里面的内容都是无效的,所以我们可以直接来个过滤双引号里面的内容。(具体实现见代码)

3)单引号问题

上面的展示代码里面也看到了,单引号里面的内容(如:if (ch == ‘{‘))可能会影响函数个数的统计,所以我们需要过滤单引号。

4)空行

这个最简单,如果string为空就是空行。包括(\t\n\r‘ ‘等等,无效字符,都算空行)。

5)“//”注释

这个较为简单,遇到//就可以进行统计,同时该行也不需要继续遍历了,直接break;然后读取下一行。

6)“/**/”注释

较麻烦,我们这里用到了代码标记,注释标记,同时还设置了当遍历到行最尾部的时候,才进行行数统计,这样避免了一行被统计多次。(具体实现见代码)

7)函数个数

首先说一下统计思路,我们统计函数的时候,只是以大括号({})为统计标记。用栈来表示,遇到左括号,入栈;遇到右括号,弹出一个左括号。知道弹到栈空,函数个数+1,

这样的话,就实现了只保留最外层那对{},里层的括号全部抵销。我们又想了一下,简化了一下,不用栈,直接用一个变量来表示括号个数,遇到左括号,++top;遇到右括号--top,直到top==0,也就相当于栈空,函数个数+1。

其实如下代码的函数个数统计还有问题:

示例:对于类、结构体、枚举体、全局数组,会被统计为一个函数。也就是说,那些在函数体外面的,但是又带有大括号({})的代码,都会被识别为函数。

以下为实现代码:

  1 #include <iostream>  2 #include <fstream>  3 #include <string>  4 using namespace std;  5   6 int main(void)  7 {  8     string line="";  9     ifstream ifs; 10     ifs.open("Test.cpp"); 11     if (!ifs) 12     { 13         cout<<"文件打开失败"<<endl; 14         exit(0); 15     } 16     ////////////////////////////////////////////// 17     //标记:双引号 斜杠星   函数      代码        注释 18     int bSyh = 0, bXgx = 0, bHs = -1, bCode = 0, bZs = 0; 19     //   ""        ‘‘        //     /*        {} 20     ///////////////////////////////////////////// 21     //个数:空行  注释    代码      公共     函数 22     int i,nKh = 0, nZs = 0, nDm = 0, nGg = 0, nHs = 0; 23     // 24     while (!ifs.eof()) 25     { 26         i = 0; 27         getline(ifs,line);    //读取一行文件 28         bCode = 0;            //该行没有代码 29         bZs = 0;              //该行没有注释 30         if (bXgx)             //bXgx 斜杠星注释标记 31             bZs = 1;          //该行有注释 32         //过滤无效符号  33         while (line[i] ==   || line[i] == \t || line[i] == \r || line[i] == \n) 34         { 35             ++i; 36         } 37         //“以下为空行统计区域:开始” 38         if (!bXgx && line[i] == \0)  //空行 39         { 40             ++nKh; 41             continue; 42         } 43         //“空行统计:结束” 44         while (1) 45         { 46             //第一次遇到双引号              引号为非转义字符(\") 47             if (!bSyh && line[i] == \" && ((i > 0 && line[i-1] != \\) || (i == 0)))  48             { 49                 ++i; 50                 bSyh = 1; 51                 continue; 52             } 53             //“正在进行双引号屏蔽....” 54             if (bSyh) 55             { 56                 //“ \”结束” 57                 if (line[i] == \" && ((i > 0 && line[i-1] != \\) || (i == 0))) 58                 { 59                     bSyh = 0; 60                 } 61                 else if (line[i] == \0)  //行末尾 62                 { 63                     if (bZs)         64                         ++nZs;        65                     if (bCode) 66                         ++nDm;       67                     if (bZs && bCode) 68                         ++nGg; 69                     break; 70                 } 71                 ++i; 72                 continue; 73             } 74             //遇到单引号(避免‘{‘,‘}‘),且非转义字符\‘,连续跳过3个(第二个‘后位置) 75             if (line[i] == \‘ && ((i > 0 && line[i-1] != \\) || (i == 0))) 76             { 77                 i += 3; 78                 continue; 79             } 80             ////注释行” 81             if (!bXgx && line[i] == / && line[i+1] == /)   82             { 83                 if (bCode)     //“前有代码,混合注释行” 84                 { 85                     ++nZs;     //注释 86                     ++nDm;     //代码 87                     ++nGg;     //公共 88                 } 89                 else          //纯注释行 90                 {  91                     ++nZs; 92                 } 93                 break;  //跳出当前行(即,内while循环),“//”后代码不做判断 94             } 95             //“/*注释开始” 96             if (!bXgx && line[i] == / && line[i+1] == *) 97             { 98                 i += 2;        //跳过/*符号 99                 bXgx = 1;      //标记“/*”开始100                 bZs = 1;       //“发现注释”101                 continue;102             }103             //“正在进行多行注释....”104             if (bXgx)105             {106                 //“*/注释结束”107                 if (line[i] == * && line[i+1] == /)108                 {109                     ++i;     //“跳过*/”注意后有一个 ++i;110                     bXgx = 0;111                 }112                 else if (line[i] == \0)  //行末尾113                 {114                     if (bCode)       //注释前有代码,即“混合行”115                     {116                         ++nDm;117                         ++nZs;       118                         ++nGg;119                     }120                     else121                     {122                         ++nZs;       //“纯注释”123                     }124                     break;125                 }126                 ++i;127                 continue;128             }129             if (line[i] == \0)130             {131                 if (bZs)        132                     ++nZs;       133                 if (bCode)134                     ++nDm;      135                 if (bZs && bCode)136                     ++nGg;137                 break;138             }139             //“以下全是有效代码区域”140             //“函数个数统计区域:开始”141             if (line[i] == {)      //记录函数左括号142             {143                 ++bHs;144             }145             else if (line[i] == }) //遇到函数右括号146             {147                 if (bHs == 0)        //“发现一个函数”148                     ++nHs;149                 --bHs;150             }151             //“函数统计:结束”152             ++i;153             bCode = 1;    //能执行到这里,说明该行存在代码154         }155     }156     157     cout<<"注释: "<<nZs<<endl;158     cout<<"代码: "<<nDm<<endl;159     cout<<"空行: "<<nKh<<endl;160     cout<<"公共: "<<nGg<<endl;161     cout<<"函数: "<<nHs<<endl;162 163     return 0;164 }

 原文地址:http://www.cnblogs.com/nchar/p/3915889.html