注釋轉換
思路:
我們先來看一下C風格的注釋, 大概有這幾種情況
// 1.一般情況
/* int i = 0; */
// 2.換行問題
/* int i = 0; */int j = ;
/* int i = 0; */
int j = ;
// 3.比對問題
/*int i = 0;/*xxxxx*/
// 4.多行注釋問題
/*
int i=0;
int j = 0;
int k = 0;
*/int k = ;
// 5.連續注釋問題
/**//**/
// 6.連續的**/問題
/***/
// 7.C++注釋問題
// /*xxxxxxxxxxxx*/
仔細觀察分析, 我們發現這裡面包含五種情況
- 正常的注釋代碼
- 遇到了斜杠 /
- 遇到了星号 *
- C風格的注釋
- C++風格的注釋
我們可以畫一個圖來幫助了解
首先理清楚 5 個狀态之間的轉換
這裡遇到 / 然後狀态變為 “遇到斜杠”, 繼續, 遇到星号 * 說明就開始了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 ()
{
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();
}
FILE *output = fopen("output.c", "w"); //打開output.c 并寫入
if (output == NULL)
{
perror("fopen");
exit();
}
CommentConvert(input, output);
if (fclose(output) == -)
{
perror("fclose");
exit();
}
if (fclose(input) == -)
{
perror("fclose");
exit();
}
return ;
}
input.c
// 1.一般情況
/* int i = 0; */
// 2.換行問題
/* int i = 0; */int j = ;
/* int i = 0; */
int j = ;
// 3.比對問題
/*int i = 0;/*xxxxx*/
// 4.多行注釋問題
/*
int i=0;
int j = 0;
int k = 0;
*/int k = ;
// 5.連續注釋問題
/**//**/
// 6.連續的**/問題
/***/
// 7.C++注釋問題
// /*xxxxxxxxxxxx*/
output.c
// 1.一般情況
// int i = 0;
// 2.換行問題
// int i = 0;
int j = ;
// int i = 0;
int j = ;
// 3.比對問題
//int i = 0;/*xxxxx
// 4.多行注釋問題
//
//int i=0;
//int j = 0;
//int k = 0;
//
int k = ;
// 5.連續注釋問題
//
//
// 6.連續的**/問題
//*
// 7.C++注釋問題
// /*xxxxxxxxxxxx*/