我必须编写一个程序来计算在文件中找到返回变量(&)地址的操作符的次数。
我使用这个简单的循环来做到这一点(不要介意提出一些问题的!feof(p)):
while (!feof(p)){
c = fgetc(p);
if (c=='&') n++; }
然而,这并不能满足我的需要。例如,如果找到AND运算符(&&),我的循环将增加变量" n"两次,但它甚至不能一次。另一件事是,如果&运算符位于单行或多行注释的范围内,不应计算。
我的问题是如何确定给定的字符/字符串(在我的情况下"&"运算符)是否在评论中?以及如何确保它确实是一个"&"操作员而不是"&&"还是一个字符串?
答案 0 :(得分:0)
正如评论中提到的,这不是一个简单的任务,可以用几行代码编写。您需要的是解析器。该解析器需要处理许多不同的情况。这是一个(可能是非详尽的)清单:
// 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写了"这是一个问题,旨在由只有基本知识的第一学期学生解决。" 在下面的评论中)
如果你被允许削减一些角落,则有更简单的方法。
这是一个完整的例子,可以削减一些角落。它处理注释和字符串,包括转义字符。但是,它不处理按位运算符。
#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中的选项。
答案 1 :(得分:-1)
要覆盖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;
}
当然,这不是一个完美的解决方案,但可以提供如何克服一些问题的想法。