今天我们来做一个经典练习题,注释转换。首先我们得先知道各种状态之间的关系:
代码如下:
#define _CRT_SECURE_NO_WARNINGS_
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
typedef enum State{
NOT_COMMENT, //不是注释。
MAYBE_IN, //可能进注释。
C_COMMENT, //C风格注释。
CPP_COMMENT, //C++风格注释。
MAYBE_OUT, //可能出注释。
}State;
int main()
{
FILE *pIn; //建立两个文件。
FILE *pOut;
int ch,nextch;
State state=NOT_COMMENT; //假设初始为不是注释状态。
const char *statestr[]={"不是注释", "可能进注释", "C风格注释", "Cpp风格注释", "可能出注释"}; //用数组记录所有状态可能性。
pIn=fopen("input.c","r"); //打开文件只能取读。
if(pIn==NULL)
{
perror(""); //如果是空文件,就输出错误原因。
system("pause");
return 1;
}
pOut=fopen("output.c","w"); //如上所述。
if(pOut==NULL)
{
perror("");
system("pause");
fclose(pIn); //关闭文件。
return 1;
}
while(1)
{
ch=fgetc(pIn); //从文件中读取一个一个的字符。
if(ch==EOF)
{
break;
}
switch(state) //用switch来分别说明各个状态的情况。
{
case NOT_COMMENT: //当是不是注释状态时。
if(ch=='/')
{
state=MAYBE_IN; //如果ch为'/',状态为可能进入,按原数继续输出。
fputc(ch,pOut);
}
else{
state=NOT_COMMENT; //否则还是不是注释状态。
fputc(ch,pOut);
}
break;
case MAYBE_IN: //当为可能进入状态时。
if(ch=='/') //如果为'/',状态为c++注释。
{
state=CPP_COMMENT;
fputc(ch,pOut);
}
else if(ch=='*') //当为*时为C风格注释。
{
state=C_COMMENT;
fputc('/',pOut);
}
else
{ //否则还是为不是注释状态。
state=NOT_COMMENT;
fputc(ch,pOut);
}
break;
case CPP_COMMENT: //当C++风格注释状态时。
if(ch=='\n')
{
state=NOT_COMMENT; //如果为换行,则变成不是注释状态。
fputc(ch,pOut);
}
else{ //否则变为C++风格注释状态。
state=CPP_COMMENT;
fputc(ch,pOut);
}
break;
case C_COMMENT: //为C风格注释时。
if(ch=='*')
{
state=MAYBE_OUT; //如果为*则变成可能出注释状态。
}
else{
state=C_COMMENT; //否则为C风格注释。
fputc(ch,pOut);
if(ch=='\n') //但是当为换行时,要将原数转为//。
{
fprintf(pOut,"//");
}
}
break;
case MAYBE_OUT: //当为可能出注释时。
if(ch=='/')
{
state=NOT_COMMENT; //如果为'/',为不是注释状态。
nextch = fgetc(pIn);
if (nextch != '\n') { //并且它下一个字符为换行时,输出换行。
fputc('\n', pOut);
}
ungetc(nextch, pIn);
}
else if (ch == '*') { //当为*时,为可能输出状态,输出*。
state = MAYBE_OUT;
fputc('*', pOut);
}
else { //否则为C风格注释状态。
state = C_COMMENT;
fputc('*', pOut);
fputc(ch, pOut);
}
break;
}
printf("%c:当前状态是 : %s\n", ch, statestr[state]); //输出最后的状态。
}
fclose(pIn); //关闭两个文件。
fclose(pOut);
system("pause");
return 0;
}