注释转换
思路:
我们先来看一下C风格的注释, 大概有这几种情况
// 1.一般情况
/* int i = 0; */
// 2.换行问题
/* int i = 0; */int j = 0;
/* int i = 0; */
int j = 0;
// 3.匹配问题
/*int i = 0;/*xxxxx*/
// 4.多行注释问题
/*
int i=0;
int j = 0;
int k = 0;
*/int k = 0;
// 5.连续注释问题
/**//**/
// 6.连续的**/问题
/***/
// 7.C++注释问题
// /*xxxxxxxxxxxx*/
仔细观察分析, 我们发现这里面包含五种情况
- 正常的注释代码
- 遇到了斜杠 /
- 遇到了星号 *
- C风格的注释
- C++风格的注释
我们可以画一个图来帮助理解
首先理清楚 5 个状态之间的转换
/* int i = 0; */
这里遇到 / 然后状态变为 “遇到斜杠”, 继续, 遇到星号 * 说明就开始了C风格的注释
状态转为 C风格注释, 然后在遇到星号 *, 进入状态 “遇到星号”, 再遇到斜杠 /, 说明C风格注释结束, 回到正常状态.
然后其他状态之间的转换关系可以根据这个图推理得出
具体实现的代码
主要用到了 fopen fclose fgetc fputc ungetc 这几个函数
FILE * fopen(const char * path, const char * mode);
//返回值:文件顺利打开后,指向该流的文件指针就会被返回。
//如果文件打开失败则返回 NULL,并把错误代码存在error中。
//一般而言,打开文件后会做一些文件读取或写入的动作,若打开文件失败
//接下来的读写动作也无法顺利进行,所以一般在 fopen() 后作错误判断及处理。
//参数 path字符串包含欲打开的文件路径及文件名
//参数 mode 字符串则代表着流形态。
int fclose( FILE *fp );
//返回值:如果流成功关闭,fclose 返回 0,否则返回EOF(-1)
//fclose是一个函数名,功能是关闭一个流。
//注意:使用fclose()函数就可以把缓冲区内最后剩余的数据输出到内核缓冲区
//并释放文件指针和有关的缓冲区。
int fgetc(FILE *stream);
//从文件指针stream指向的文件中读取一个字符
//读取一个字节后,光标位置后移一个字节。
//这个函数的返回值,是返回所读取的一个字节。
//如果读到文件末尾或者读取出错时返回EOF(-1)
int fputc (int c, FILE *fp);
//将字符ch写到文件指针fp所指向的文件的当前写指针的位置
//返回值:在正常调用情况下,函数返回写入文件的字符的ASCII码值
//出错时,返回EOF(-1)。
//当正确写入一个字符或一个字节的数据后
//文件内部写指针会自动后移一个字节的位置
int ungetc(int c, FILE *stream);
//把一个(或多个)字符退回到steam代表的文件流中,可以理解成一个“计数器”
//c: 要写入的字符
//stream: 文件流指针,必须是输入流不能是输出流
//返回值:字符c - 操作成功,EOF - 操作失败(int)
实现代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef enum State
{
NORMAL, //正常的代码
MEET_SLASH, //遇到 '/'
CPP_COMMENT, //C++ 风格注释
C_COMMENT, //C 风格注释
MEET_ASTERISK, //遇到 '*'
} State;
void CommentConvert(FILE *input, FILE *output)
{
int ch, nextCh;
State state = NORMAL;
while (1)
{
ch = fgetc(input);
if (ch != EOF)
{
switch (state)
{
case NORMAL:
if (ch == '/')
{
fputc(ch, output);
state = MEET_SLASH;
//fputc(ch, output);
}
else
{
fputc(ch, output);
state = NORMAL;
}
break;
case MEET_SLASH:
if (ch == '/')
{
fputc(ch, output);
state = CPP_COMMENT;
}
else if (ch == '*')
{
fputc('/', output);
state = C_COMMENT;
//fputc('/', output);
}
else
{
fputc(ch, output);
state = NORMAL;
}
break;
case MEET_ASTERISK:
if (ch == '/')
{
nextCh = fgetc(input);
if (nextCh == '\n')
{
;
}
else
{
fputc('\n', output);
}
ungetc(nextCh, input);
state = NORMAL;
}
else if (ch == '*')
{
fputc('*', output);
state = MEET_ASTERISK;
}
else
{
fputc('*', output);
fputc(ch, output);
state = C_COMMENT;
}
break;
case CPP_COMMENT:
if (ch == '\n')
{
//fputc('\r', output);
fputc(ch, output);
state = NORMAL;
}
else
{
fputc(ch, output);
state = CPP_COMMENT;
}
break;
case C_COMMENT:
if (ch == '*')
{
//fputc(ch, output);
state = MEET_ASTERISK;
}
else
{
//nextCh = fgetc(input);
if (ch == '\n')
{
fputc(ch, output);
fputc('/', output);
fputc('/', output);
}
else
{
fputc(ch, output);
//ungetc(nextCh, input);
}
state = C_COMMENT;
}
break;
}
}
else
{
break;
}
}
}
int main()
{
FILE *input = fopen("input.c", "r"); //打开input.c 并读取
if (input == NULL)
{
perror("fopen");
exit(0);
}
FILE *output = fopen("output.c", "w"); //打开output.c 并写入
if (output == NULL)
{
perror("fopen");
exit(0);
}
CommentConvert(input, output);
if (fclose(output) == -1)
{
perror("fclose");
exit(0);
}
if (fclose(input) == -1)
{
perror("fclose");
exit(0);
}
return 0;
}
input.c
// 1.一般情况
/* int i = 0; */
// 2.换行问题
/* int i = 0; */int j = 0;
/* int i = 0; */
int j = 0;
// 3.匹配问题
/*int i = 0;/*xxxxx*/
// 4.多行注释问题
/*
int i=0;
int j = 0;
int k = 0;
*/int k = 0;
// 5.连续注释问题
/**//**/
// 6.连续的**/问题
/***/
// 7.C++注释问题
// /*xxxxxxxxxxxx*/
output.c
// 1.一般情况
// int i = 0;
// 2.换行问题
// int i = 0;
int j = 0;
// int i = 0;
int j = 0;
// 3.匹配问题
//int i = 0;/*xxxxx
// 4.多行注释问题
//
//int i=0;
//int j = 0;
//int k = 0;
//
int k = 0;
// 5.连续注释问题
//
//
// 6.连续的**/问题
//*
// 7.C++注释问题
// /*xxxxxxxxxxxx*/