3.3 删除C程序注释
【例3.3】删除合法C程序的注释部分,命令行格式为:rcomment inputFile outputFile。
题目分析
程序遇到注释的开始“/”时,调用RemoveComment函数跳过注释部分,直到遇到匹配的注释结束“/”。
需要注意,当遇到多个连续的斜杠‘/’但无星号‘’匹配时,应保留斜杠‘/’。当遇到前单引号或前双引号时,引号内的“/”和“*/”不应当做注释处理。主程序调用EchoQuote函数,保留引号内的所有字符,直到遇到匹配的后前单引号或后双引号。还应注意,不要将引号内转义符‘’后的引号匹配成后引号。
参考程序
/*
* 文件名: rcomment.c
* 描述: 删除合法C程序的注释部分。
* 命令行格式为:rcomment inputFile outputFile
* 作者: 刘博
*/
#include <stdio.h>
#include <stdlib.h>
void RemoveComment(FILE *fp);
void EchoQuote(int c, FILE *fpIn, FILE *fpOut);
int main(int argc, char *argv[])
{
FILE *fpIn, *fpOut;
int c, n;
/* 检查命令行参数个数 */
if (argc != 3) {
printf("Usage: rcomment InputFile OutputFile\n");
exit(1);
}
/* 打开文件 */
if ((fpIn = fopen(argv[1], "r")) == NULL) {
printf("rcomment: can't open %s\n", argv[1]);
exit(1);
}
if ((fpOut = fopen(argv[2], "w")) == NULL) {
printf("rcomment: can't open %s\n", argv[2]);
exit(1);
}
while ((c = fgetc(fpIn)) != EOF) {
if (c == '/') {
if ((n = fgetc(fpIn)) == '*') { /* 注释开始 */
RemoveComment(fpIn);
} else if (n == '/'){ /* 处理连续多个斜杠 */
fputc(c, fpOut);
ungetc(n, fpIn);
} else { /* 非注释部分 */
fputc(c, fpOut);
fputc(n, fpOut);
}
} else if (c == '\'' || c == '\"') { /* 单引号和双引号内处理 */
EchoQuote(c, fpIn, fpOut);
} else {
fputc(c, fpOut); /* 非注释部分 */
}
}
/* 关闭文件 */
fclose(fpIn);
fclose(fpOut);
}
void RemoveComment(FILE *fp)
{
int c, n;
c = fgetc(fp);
n = fgetc(fp);
while (c != '*' || n != '/') { /* 寻找注释结尾 */
c = n;
n = fgetc(fp);
}
}
void EchoQuote(int c, FILE *fpIn, FILE *fpOut)
{
int n;
fputc(c, fpOut);
while ((n = fgetc(fpIn)) != c) { /* 寻找后引号 */
fputc(n, fpOut);
if (n == '\\') { /* 引号内转义符后的引号非后引号 */
fputc(fgetc(fpIn), fpOut);
}
}
fputc(n, fpOut);
}
习题
- 比较两个文本文件并打印出它们第一个不相同的行(文件每行字符数不多于80)。
- 文本文件num1.txt和num2.txt中各有一组用空格分隔的整数,将num1.txt和num2.txt联合排序,并将结果保存在num3.txt中,如图 3-1所示。
现有两个文本文件db1.txt和db2.txt。db1.txt中第一列为姓名,第二列为英语成绩;db2.txt中第一列为姓名,第二列为数学成绩。通过姓名字段将db1.txt文件关联到db2.txt文件生成db3.txt文件。db3.txt文件第一列为姓名,第二列为英语成绩,第三列为数学成绩,第四列为平均成绩,如图 3-2所示。
- 检查C源程序的圆括号和大括号是否匹配。正确的例子如({((…)(…))}()),不正确的例子如{(})。