在C语言中计算注释行中字符的数量

3

我需要计算一个供应作为标准输入的C程序中评论中的字符数。 这是我的函数,但由于某些原因它没有正确地计数。 你能帮我吗?

int characters(FILE *file)
{
     int i=0;
     char ch[500], *p;
     while (fgets(ch, sizeof(ch),file)!=NULL)
     {
        p=ch;
        while (*p)
        { 
           if (*p=='/')
           { 
              p++;
              if (*p=='*')
              {
                 p++;
                 while (*p!='*' && *(p++)!='/')
                 {
                    i++;
                    p++;
                 }
              }
           }
           else
              p++;

         }


   return i;
}

2
如果有人在程序中的字符串中使用类似于注释开头的字符,会发生什么情况?或者如果注释被打开了,但从未关闭呢?当 '/' 和 '*' 来自不同的 fgets 调用时会发生什么情况? - Art
对不起,我觉得你没有打开文件... - Alberto Bonsanto
这段代码很难理解和维护。正如Art所说,它没有涵盖特殊情况。我认为在这里使用状态机是更好的选择,并且我已经提供了一个相关的答案。 - Richard
5个回答

5

我认为问题出在最内层的循环中:

while (*p!='*' && *(p++)!='/')

应该是

while (*p!='*' && *(p+1)!='/')

但是,如果它遇到像这样的内容,就会出错:
/* comment * */

因为条件语句的第一部分*p!='*'在第一个星号处就已经不成立了,所以你可以采用以下方式:

while (!(*p=='*' && *(p+1)=='/')) {
   p++;
   i++;
}

注意:如果行被打断,您将会得到一个分段错误。
    /* comment * \n
    */

您仍需处理此问题,但应将*p添加到内部循环中:

while (*p && !(*p=='*' && *(p+1)=='/')) {
   p++;
   i++;
}

1
我怀疑这可能是你的问题:
while (*p!='*' && *(p++)!='/')

请记住,p++ 的值是在增量之前计算的;实际上,测试的结果是

while (*p != '*' && *p != '/')

所以如果*p的值为*,测试将会失败。请更改为

while (*p != '*' && *(++p) != '/')

1

你的代码吓到我了。

有很多指针在运作,还有嵌套循环。

在那里很容易出现逻辑错误,如果需要进行更改,代码也很难扩展。

我可以建议一个不同的解决方案吗?

一个状态机

我们将一次读入文件一个字符,并跟踪机器所处的状态。然后,我们将使用这个来决定我们是否在注释中。

#include <cstdio>
#define S_CODE          1
#define S_ONESLASH      2
#define S_LINECOMMENT   3
#define S_BLOCKCOMMENT  4
#define S_BLOCKSTAR     5

int characters(FILE *file){
    int ccount=0;
    char ch;
    int state=S_CODE;
     while ((ch=fgetc(file))!=EOF){
        switch(state){
            case S_CODE:
                if (ch=='/')
                    state=S_ONESLASH;
                break;

            case S_ONESLASH:
                if (ch=='/')
                    state=S_LINECOMMENT;
                else if (ch=='*')
                    state=S_BLOCKCOMMENT;
                else
                    state=S_CODE;
                break;

            case S_LINECOMMENT:
                if (ch=='\n')
                    state=S_CODE;
                else
                    ccount++;
                break;

            case S_BLOCKCOMMENT:
                if (ch=='*')
                    state=S_BLOCKSTAR;
                ccount++;
                break;

            case S_BLOCKSTAR:
                if (ch=='/')
                    state=S_CODE;
                else if (ch=='*')
                    state=S_BLOCKSTAR;
                else
                    state=S_CODE;
                ccount++;
                break;
        }
    }
    return ccount;
}

int main(int argc, char **argv){
    FILE *fin=fopen(argv[1],"r");
    printf("%d\n",characters(fin));
}

请注意我们如何使用字符/*\n来标记机器不同状态之间的转换,以及在某些状态下我们增加注释字符计数器,而在其他状态下则不增加。我认为这样更容易跟踪这里发生的事情。

0

看起来工作正常

int characters(FILE *file)
{
    int i = 0;
    char ch[500], *p;
    fread(ch, sizeof(char), 500, file);
    p = ch;
    while (*p)
    {
        if (*p=='/' && *(p+1) == '*')
        { 
            while (*p && (*p != '*' && *(p+1) != '/')) 
                ++p;
            ++i;
        }
        ++p;
    }
    return i;
}

0
问题如前所述,出现在代码行while (*p!='*' && *(p++)!='/')中。在这种情况下,如果第一部分“触发”,则仅评估语句的第二部分(*(p++)!='/'),因此如果找到星号,则会增加p

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接