程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++統計代碼注釋行數 & 有效代碼行數 & 代碼注釋公共行 & 函數個數

C++統計代碼注釋行數 & 有效代碼行數 & 代碼注釋公共行 & 函數個數

編輯: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 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 <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                     else 121                     { 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 }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved