C程序不会删除占据整行的评论

时间:2015-02-22 11:10:57

标签: c

所以我正在阅读K& R C书,我的代码中有一个我根本想不通的错误。

该程序应该删除C程序中的所有注释。显然我只是使用stdin

#include <stdio.h>

int getaline (char s[], int lim);

#define MAXLINE 1000 //maximum number of characters to put into string[]

#define OUTOFCOMMENT 0
#define INASINGLECOMMENT 1
#define INMULTICOMMENT 2

int main(void)
{
    int i;
    int isInComment;
    char string[MAXLINE];

    getaline(string, MAXLINE);

    for (i = 0; string[i] != EOF; ++i) {
        //finds whether loop is in a comment or not
        if (string[i] == '/') {
            if (string[i+1] == '/')
                isInComment = INASINGLECOMMENT;
            if (string[i+1] == '*')
                isInComment = INMULTICOMMENT;
        }
        //fixes the problem of print messing up after the comment
        if (isInComment == INASINGLECOMMENT && string[i] == '\0')
            printf("\n");

        //if the line is done, restates all the variables
        if (string[i] == '\0') {
            getaline(string, MAXLINE);
            i = 0;
            if (isInComment != INMULTICOMMENT)
                isInComment = OUTOFCOMMENT;
        }

        //prints current character in loop
        if(isInComment == OUTOFCOMMENT && string[i] != EOF)
            printf("%c", string[i]);

        //checks to see of multiline comment is over
        if(string[i] == '*' && string[i+1] == '/' ) {
            ++i;
            isInComment = OUTOFCOMMENT;
        }

    }
    return 0;

}

所以除了一个问题外,这个工作很好。每当一行以评论开头时,它就会打印出该评论。

所以,例如,如果我有一行只是

//this is a comment

在评论开始之前没有任何内容,它将打印该评论,即使它不应该。

我以为自己取得了很好的进展,但这个错误确实让我感到震惊。我希望这不是我错过的一件非常容易的事。

编辑:忘记getaline功能

//puts line into s[], returns length of that line
int getaline(char s[], int lim)
{
    int c, i;

    for (i = 0; i < lim-1 && (c = getchar()) != '\n'; ++i)
        s[i] = c;
    if (c == '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

2 个答案:

答案 0 :(得分:4)

    if (string[i] == '\0') {
        getaline(string, MAXLINE);
        i = 0;
        if (isInComment != INMULTICOMMENT)
            isInComment = OUTOFCOMMENT;
    }

当你开始一个新行时,你将i初始化为0.但是在下一次迭代中:

for (i = 0; string[i] != EOF; ++i)

i会递增,因此您将开始索引为1的新行。因此,当行以//开头时存在错误。

如果您改为编写,可以看到它解决了问题:

    if (string[i] == '\0') {
        getaline(string, MAXLINE);
        i = 0;
        if (isInComment != INMULTICOMMENT)
            isInComment = OUTOFCOMMENT;
    }

虽然它通常被认为是在循环内修改for循环索引的坏样式。您可以以更易读的方式重新设计实现。

答案 1 :(得分:4)

您的代码中存在许多问题:

  • isInComment未在函数main中初始化。
  • 正如其他人指出的那样,string[i] != EOF是错误的。您需要更精确地测试文件结尾,尤其是对于不以换行结束的文件。此测试仅在char类型已签名且EOF为有效signed char值时有效。尽管如此,它仍会错误地停留在一个流浪的\377字符上,这个字符在字符串或注释中是合法的。
  • 当您检测到行尾时,您会读取另一行并将i重置为0,但在再次测试之前,我将通过for循环递增单行评论......因此错误!
  • 您不会处理/* // */// /*
  • 等特殊情况
  • 你不处理字符串。这不是评论:"/*",也不是:'//'
  • 您未在行尾处理\(转义换行)。这可用于扩展单行注释,字符串等。有更多与\处理相关的微妙案例,如果你真的想要完整性,你也应该处理三字符。
  • 您的实施对行大小有限制,不需要这样做。

你被分配的问题有点棘手。不是读取和解析行,而是一次读取一个字符并实现状态机来解析转义的换行符,字符串和两种注释样式。如果你用这种方法做到这一点,代码就不会太难了。