所以我正在阅读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;
}
答案 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循环递增单行评论......因此错误!/* // */
或// /*
"/*"
,也不是:'//'
\
(转义换行)。这可用于扩展单行注释,字符串等。有更多与\
处理相关的微妙案例,如果你真的想要完整性,你也应该处理三字符。你被分配的问题有点棘手。不是读取和解析行,而是一次读取一个字符并实现状态机来解析转义的换行符,字符串和两种注释样式。如果你用这种方法做到这一点,代码就不会太难了。