【问题标题】:C Program won't remove comments that take up the whole lineC 程序不会删除占整行的注释
【发布时间】:2015-02-22 11:10:57
【问题描述】:

所以我正在阅读 K&R C 这本书,但我的代码中有一个我根本无法弄清楚的错误。

该程序应该从 C 程序中删除所有 cmets。显然我只是在使用标准输入

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

【问题讨论】:

  • “getaline”功能有什么?
  • string[i] != EOF 似乎不对。我觉得应该是string[i] != '\0'
  • string[i] != EOF; --> string[i] != 0; 开始。

标签: c


【解决方案1】:

你的代码有很多问题:

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

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

【讨论】:

  • 当。我需要处理我的代码。感谢您指出所有错误。
  • 一开始吸这么烂正常吗?非常令人沮丧。
  • 这个不用担心,你要解决的问题其实挺难的。这里有一个重复:stackoverflow.com/questions/19238390/…,但他们也没有正确。
【解决方案2】:
    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 循环索引通常被认为是不好的风格。您可以以更易读的方式重新设计您的实现。

【讨论】:

    猜你喜欢
    • 2014-08-27
    • 2010-11-04
    • 1970-01-01
    • 2021-01-04
    • 2013-01-10
    • 2023-03-16
    • 2012-06-16
    • 1970-01-01
    • 2012-10-15
    相关资源
    最近更新 更多