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;
}
4

5 回答 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++;
}
于 2012-11-14T15:21:33.853 回答
1

我怀疑这是你的问题:

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

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

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

因此,如果*p评估为*,则测试将失败。将其更改为

while (*p != '*' && *(++p) != '/')
于 2012-11-14T15:24:57.307 回答
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我认为跟踪这里发生的事情要容易得多。

于 2012-11-14T15:51:52.980 回答
0

如前所述,问题在这种情况下是一致的,仅当第一部分“触发”时才评估while (*p!='*' && *(p++)!='/') 语句 () 的第二部分,因此如果找到星号则递增。*(p++)!='/'p

于 2012-11-14T15:33:06.753 回答
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;
}
于 2012-11-14T15:42:03.917 回答