设为首页 加入收藏

TOP

C++代码注释行和函数个数统计(一)
2015-07-20 17:53:38 来源: 作者: 【 】 浏览:5
Tags:代码 注释 函数个数 统计

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

下面稍微解释一下问题,

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

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

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

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

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

复制代码
 1 #include 
  
   
 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 line
16     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 line
26     pure //comments line;"*/......"look there*/
27     printf("test \" escape char");
28     //and the follow,maybe affect the count of function
29     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 
  
   
  2 #include 
   
     3 #include 
    
      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<<"文件打开失败"<
     
       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 else 121 { 122 ++nZs; //“纯注释” 123 } 124 break; 125 } 126 ++i; 127 continue; 128 } 129 if (line[i] == '\0')
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇UVA - 12005 Find Solutions (最.. 下一篇POJ 3090 Visible Lattice Points

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: