如何检查字符是否在C中的注释范围内
How to check if a character is inside the scope of a comment in C
我必须编写一个程序来计算运算符 returns 在文件中找到变量 (&) 地址的次数。
我使用这个简单的循环来这样做(不要介意提出一些问题的 !feof(p)):
while (!feof(p)){
c = fgetc(p);
if (c=='&') n++; }
但是,这并不能满足我的需求。例如,如果找到 AND 运算符 (&&),我的循环将增加变量 "n" 两次,但不能增加一次。另一件事是,如果 & 运算符出现在单行或多行注释的范围内,则不应计算在内。
我的问题是如何确保给定的 character/string(在我的例子中是“&”运算符)是否在评论中?以及如何确保它确实是“&”运算符而不是“&&”或字符串的一部分?
如评论中所述,这不是几行代码就可以完成的小任务。你需要的是一个解析器。该解析器需要处理许多不同的情况。这是一个(可能不详尽的)列表:
- 一行评论:
// This is a comment
- 多行评论:
/* This is a comment */
- 字符数:
char c='&'
- 字符串文字:
strcmp(str, "A string with a & in it")
- 按位运算符:
int a = mask & b
您还需要决定如何处理不正确的输入。程序应该能够检测到不正确的 c 代码,还是应该假定所有输入都是正确的?另一件需要考虑的事情是如何处理 #include
。您是否也想计算包含文件中出现的次数? (我假设不是,但这表明存在问题)
如果您希望它 100% 准确地仅查找地址运算符,那么这超出了您的知识范围。 (OP 在下面的评论中写道 "This is a problem is designed to be solved by 1st-semester students with only basic knowledge.")
如果允许您偷工减料,还有更简单的方法。
这里是一个完整的例子,只是偷工减料。它处理注释和字符串,包括转义字符。但是,它不处理按位运算符。
#include <stdio.h>
#include <stdlib.h>
#define INPUT "input.c"
int main()
{
FILE *f;
if ((f = fopen(INPUT, "r")) == NULL)
{
perror (INPUT);
return (EXIT_FAILURE);
}
char c, p=0;
int n=0;
while((c = fgetc(f)) != EOF)
{
if(c == '/' && p == '/') {
while((c = fgetc(f)) != EOF) {
// If we read // then we throw away the rest of the line
if( c == '\n' ) {
break;
}
}
if( c == EOF) {
goto end;
}
}
else if(c == '*' && p == '/') {
// If we read /* then we throw away everything until we have read */
while((c = getc(f)) != EOF) {
if( c == '*' ) {
if((c = getc(f)) != EOF)
if( c == '/')
break;
}
} if ( c == EOF) {
goto end;
}
}
else if(c == '"') {
// Read until end of string
while((c = getc(f)) != EOF) {
if(c == '\') {
if((c = getc(f)) == EOF)
goto end;
}
else if(c == '"')
break;
}
}
else if(c == '\'') {
while((c = getc(f)) != EOF) {
if(c == '\') {
if((c = getc(f)) == EOF)
goto end;
}
else if(c == '\'')
break;
} if ( c == EOF)
goto end;
}
else if(c == '&') {
printf("hej");
if(p == '&')
n--;
else
n++;
}
p=c;
}
end:
printf("\n\nExited at pos %ld\n", ftell(f));
printf("Number of address operators: %d\n", n);
}
它的工作方式有点像这样:当它看到评论开始时,它会读取并丢弃所有内容,直到评论结束或 EOF。它对字符串也是如此。
在此输入上:
// Test &
/* Also
&
test */
// "
int main()
{
/* " //
*/
// /*
char str[]="hej&\"";
char c='&';
char k='\'';
int a, b;
int * p;
p=&a;
int c=a&b;
int q=a&&b;
}
// Test &
/* Also
&
test */
它报告预期的结果2。如果它打印1会更好,但是正如我提到的,它不能处理按位运算符,因此将其算作地址运算符。解决这个问题会使事情变得更加复杂。
是的,我正在使用 goto
,因为在这种情况下它非常方便。在 C++ 中,我会使用异常,但这在 C 中不是一个选项。
要涵盖 C 语言中的所有案例将非常困难,您可能需要一个合适的解析器,但如果您只打算将其用于练习 - 以便在问题中描述的案例中工作,你可以这样实现:
char previous = 0;
int single_line_comment = 0;
int multi_line_comment = 0;
int in_string = 0;
int in_char = 0;
while (!feof(p)){
c = fgetc(p);
if (c == '&' && !single_line_comment && !multi_line_comment && !in_string && !in_char)
{
if(previous == '&')
n--;
else
n++;
}
else if(c == '/' && prev == '/' && !multi_line_comment && !in_string && !in_char)
single_line_comment = 1;
else if(prev == '/' && c == '*' && !single_line_comment && !in_string && !in_char)
multi_line_comment = 1;
else if(c == '\n' && !multi_line_comment && !in_string && !in_char)
single_line_comment = 0;
else if(prev == '*' && c == '/' && !single_line_comment && !in_string && !in_char)
multi_line_comment = 0;
else if(c = '"' && !single_line_comment && !multi_line_comment && !in_char)
in_string = !in_string;
else if(c = '\'' && !single_line_comment && !multi_line_comment && !in_string)
in_char = !in_char;
previous = c;
}
当然这不是完美的解决方案,但可以提供一些解决方案。
我必须编写一个程序来计算运算符 returns 在文件中找到变量 (&) 地址的次数。
我使用这个简单的循环来这样做(不要介意提出一些问题的 !feof(p)):
while (!feof(p)){
c = fgetc(p);
if (c=='&') n++; }
但是,这并不能满足我的需求。例如,如果找到 AND 运算符 (&&),我的循环将增加变量 "n" 两次,但不能增加一次。另一件事是,如果 & 运算符出现在单行或多行注释的范围内,则不应计算在内。
我的问题是如何确保给定的 character/string(在我的例子中是“&”运算符)是否在评论中?以及如何确保它确实是“&”运算符而不是“&&”或字符串的一部分?
如评论中所述,这不是几行代码就可以完成的小任务。你需要的是一个解析器。该解析器需要处理许多不同的情况。这是一个(可能不详尽的)列表:
- 一行评论:
// This is a comment
- 多行评论:
/* This is a comment */
- 字符数:
char c='&'
- 字符串文字:
strcmp(str, "A string with a & in it")
- 按位运算符:
int a = mask & b
您还需要决定如何处理不正确的输入。程序应该能够检测到不正确的 c 代码,还是应该假定所有输入都是正确的?另一件需要考虑的事情是如何处理 #include
。您是否也想计算包含文件中出现的次数? (我假设不是,但这表明存在问题)
如果您希望它 100% 准确地仅查找地址运算符,那么这超出了您的知识范围。 (OP 在下面的评论中写道 "This is a problem is designed to be solved by 1st-semester students with only basic knowledge.")
如果允许您偷工减料,还有更简单的方法。
这里是一个完整的例子,只是偷工减料。它处理注释和字符串,包括转义字符。但是,它不处理按位运算符。
#include <stdio.h>
#include <stdlib.h>
#define INPUT "input.c"
int main()
{
FILE *f;
if ((f = fopen(INPUT, "r")) == NULL)
{
perror (INPUT);
return (EXIT_FAILURE);
}
char c, p=0;
int n=0;
while((c = fgetc(f)) != EOF)
{
if(c == '/' && p == '/') {
while((c = fgetc(f)) != EOF) {
// If we read // then we throw away the rest of the line
if( c == '\n' ) {
break;
}
}
if( c == EOF) {
goto end;
}
}
else if(c == '*' && p == '/') {
// If we read /* then we throw away everything until we have read */
while((c = getc(f)) != EOF) {
if( c == '*' ) {
if((c = getc(f)) != EOF)
if( c == '/')
break;
}
} if ( c == EOF) {
goto end;
}
}
else if(c == '"') {
// Read until end of string
while((c = getc(f)) != EOF) {
if(c == '\') {
if((c = getc(f)) == EOF)
goto end;
}
else if(c == '"')
break;
}
}
else if(c == '\'') {
while((c = getc(f)) != EOF) {
if(c == '\') {
if((c = getc(f)) == EOF)
goto end;
}
else if(c == '\'')
break;
} if ( c == EOF)
goto end;
}
else if(c == '&') {
printf("hej");
if(p == '&')
n--;
else
n++;
}
p=c;
}
end:
printf("\n\nExited at pos %ld\n", ftell(f));
printf("Number of address operators: %d\n", n);
}
它的工作方式有点像这样:当它看到评论开始时,它会读取并丢弃所有内容,直到评论结束或 EOF。它对字符串也是如此。
在此输入上:
// Test &
/* Also
&
test */
// "
int main()
{
/* " //
*/
// /*
char str[]="hej&\"";
char c='&';
char k='\'';
int a, b;
int * p;
p=&a;
int c=a&b;
int q=a&&b;
}
// Test &
/* Also
&
test */
它报告预期的结果2。如果它打印1会更好,但是正如我提到的,它不能处理按位运算符,因此将其算作地址运算符。解决这个问题会使事情变得更加复杂。
是的,我正在使用 goto
,因为在这种情况下它非常方便。在 C++ 中,我会使用异常,但这在 C 中不是一个选项。
要涵盖 C 语言中的所有案例将非常困难,您可能需要一个合适的解析器,但如果您只打算将其用于练习 - 以便在问题中描述的案例中工作,你可以这样实现:
char previous = 0;
int single_line_comment = 0;
int multi_line_comment = 0;
int in_string = 0;
int in_char = 0;
while (!feof(p)){
c = fgetc(p);
if (c == '&' && !single_line_comment && !multi_line_comment && !in_string && !in_char)
{
if(previous == '&')
n--;
else
n++;
}
else if(c == '/' && prev == '/' && !multi_line_comment && !in_string && !in_char)
single_line_comment = 1;
else if(prev == '/' && c == '*' && !single_line_comment && !in_string && !in_char)
multi_line_comment = 1;
else if(c == '\n' && !multi_line_comment && !in_string && !in_char)
single_line_comment = 0;
else if(prev == '*' && c == '/' && !single_line_comment && !in_string && !in_char)
multi_line_comment = 0;
else if(c = '"' && !single_line_comment && !multi_line_comment && !in_char)
in_string = !in_string;
else if(c = '\'' && !single_line_comment && !multi_line_comment && !in_string)
in_char = !in_char;
previous = c;
}
当然这不是完美的解决方案,但可以提供一些解决方案。