去除C/C++程序代码中的注释
最近搞软件著作权,去除代码空行和注释比较麻烦,想写个程序自动去除,去网上搜了下,发现有类似的程序,不过只有去除注释。鉴于word中可以去除空行(用^p^p替换^p),先用网上的代码,以后有时间写个完整版的,遍历代码文件夹搜索指定的格式,自动生成最终结果。
注:这个博客的方法不是最好的,最好的方法是使用正则表达式(2013.12.03)
转载自http://blog.csdn.net/mznewfacer/article/details/6942857
程序员面试宝典上面的题目有很多是很经典的问题,可供我们思考,而且会对我们面试有很大好处。
下面是第45页的一个题目:编写一个函数,实现把C/C++程序代码中的注释去掉,我开始看的时候总是看不懂,后来在网上看到一个网友详细的分析了其代码,但是我看了之后觉得有好多地方他分析的都不对,于是,我自己又花了半天的时间分析了一遍,觉得自己理解了,下面给出我的分析语句。如果还有不严谨的部分,请指教!
/********************************************************
功能:去除C/C++中的注释
输入:指向C/C++程序代码的指针及长度
来源:程序员面试宝典第45页
分析:一次读取一行,分两种情况,因为有两种注释:
(1)在读取到的一行中查找“//”,如果找到,则把“//”及其后的部分扔掉。
(2)在读取到的一行中查找“/*”,记录位置pos1,然后再在这行中查找“*/”,如果找到,也记录位置pos2,扔掉它们与其中的内容,以pos2开始,继续查找“/*”;如果在当前行中没有找到,则去掉当前行中“/*”及其后的内容,读取新的一行,查找“*/”,如没有。则去掉读取到的这一行,再读一行,查找“*/”,如找到,记录位置pos2,去掉这一行的0到pos2之间的字符。
(3)进行步骤1、步骤2,直到程序结束。
编程时要考虑的特殊情况i:
“”中的“//”“/*”
''中的“//”“/*”
“//”与“/*”的嵌套关系,比如///* 、/* //*/
*********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
void remove_comment(char *buf, size_t size)
{
char *p, *end, c; //p-动态移动的字符指针,end-指向文件末尾的字符指针,c-存储没一个p指向的字符
char *sq_start, *dq_start; //sq_start-单引号开始位置(single),dq_start-双引号开始(double)
char *lc_start, *bc_start; //lc_start-//的开始位置,bc_start-/*的开始位置
size_t len; //记录某符号结束和开始的位置之差(长度,偏移量)
p = buf;
end = p + size;
sq_start = dq_start = NULL;
lc_start = bc_start = NULL;
while (p < end) /*当指针没有到达文件末尾 */
{
c = *p; //用字符变量c存储指针指向的字符
switch (c) //根据c的值做相应处理
{
case '\'': /*处理单引号*/
{
if (dq_start || lc_start || bc_start) //当遇到过双引号、//或/*的时候,则不需要再判断'//'的情况了。
{
p++;
continue; //继续下一个,对while而言的
}
/*******************************以下是没有遇到过双引号或//或/*的时候*******************************/
if (sq_start == NULL) /****如果未遇到单引号****/
{
sq_start = p++; //start指向单引号的开始位置,p指向下一个
}
else /*如果遇到过单引号,sq_start指向单引号开始位置*/
{
len = (p++) -sq_start;
if (len == 2 && *(sq_start+1) == '\\')
{
/*若遇到 “ '\'' ”这种情况则两个单引号并未匹配,遇到的“'”是“\' ”中的,而不是与sq_start所指向单引号匹配*/
continue;
}
sq_start = NULL; //否则将sq_start置位为NULL
}
/*******************************以上是没有遇到过双引号或//或/*的时候*******************************/
break;
}
case '\"': /*处理双引号*/
{
if (sq_start || lc_start || bc_start) //当遇到过单引号、//或/*的时候,则不需要处理
{
p++;
continue;
}
/*****************以下是没有遇到过单引号或//或/*的时候*****************/
if (dq_start == NULL) /*如果没有遇到过双引号*/
{
dq_start = p++; //标记遇到了双引号
}
else if (*((p++) -1) =='\\')
{
/*若遇到 “" ab\''cd" ”这种情况则两个双引号并未匹配,遇到的“"”是“\"”中的,而不是与dq_start所指向双引号匹配*/
continue;
}
dq_start = NULL; //如果双引号中不是//,标记为NULL
/*****************以上是没有遇到过单引号或//或/*的时候*****************/
}
case '/': //斜杠,注意这个斜杠也可以是'//',"//",//,/*/中的第二个斜杠,但会在下面第二行代码中被忽略掉
{
if (sq_start || dq_start || lc_start || bc_start) //如果是单引号、双引号、斜杠、/*的后面
{
p++;
continue;
}
/***********************下面是遇到注释//或/*的时候****************************/
c = *(p + 1); //否则c取p指向字符的下一个字符
if (c == '/') //遇到了双斜杠
{
lc_start = p; //标记双斜杠的开始
p += 2; //p指向双斜杠后面的字符
}
else if (c == '*') //遇到了/*
{
bc_start = p; //标记/*的开始
p += 2; //p指向/*后面的字符
}
/*************************上面是遇到注释//或/*的时候**************************/
else
{
p++;
}
}
case '*': //星号,同斜杠,但少了如果遇到/*的情况,因为遇到这种情况后,要判断是不是遇到结束的地方*/了
{
if (sq_start || dq_start || lc_start) //如果是单引号、双引号、斜杠、/*的后面
{
p++;
continue;
}
if (*(p + 1) != '/') //如果星号后面紧跟的不是斜杠,那么忽略过。
{
p++;
continue;
}
p += 2; //否则p指向斜杠后面那个字符。注意下面的清空语句,p指向的那个字符并不会被清除。
memset(bc_start, ' ', p-bc_start); //清空/* …… */中间的内容包括注释符号本身。
bc_start = NULL;
break;
}
case '\n': /*换行符,主要处理遇到双斜杠时,需要清除双斜杠到\n的前面的字符*/
{
if (lc_start == NULL) //如果还没有遇到双斜杠,那么忽略
{
p++;
continue;
}
c = *(p - 1);
/*如果遇到过双斜杠,清空双斜杠本身和到\n前面的那个字符,p指向下一个字符,/r是回车符(光标退回到最前面),这里要判断
c == '\r'是因为在UNIX系统下文件结尾的换行只有\n,而windows系统下文件结尾的换行为\r\n */
memset(lc_start, ' ', (c == '\r'? ((p++) -1) : p++) - lc_start);
lc_start = NULL;
break;
}
default:
p++;
break;
}
/****************************************************
如果遇到双斜杠,这个if语句存在的意义在于万一最后
一行代码是带有双斜杠但没有给换行符\n的,也要清除掉。
*****************************************************/
if (lc_start)
{
memset(lc_start, ' ', p - lc_start);
}
}
}
/**********************************************
main函数的开始
***********************************************/
int main (int argc, char *argv[])
{
int fd, n;
char buf[102400];
if (argc != 2)
{
printf("command error: Input as ./command <file>\n");
}
fd = open(argv[1], O_RDONLY); /*只读打开*/
if (fd == -1)
{
return -1;
}
n = read(fd, buf, sizeof(buf));
if (n == -1 || n == 0)
{
close(fd);
return -1;
}
printf("test\n");
remove_comment(buf, n);
*(buf + n) = '\0';
printf("%s", buf);
close(fd);
return 0;
}
去除C/C++程序代码中的注释的更多相关文章
- 程序代码中退出函数exit()与返回函数return ()的区别
程序代码中退出函数exit()与返回函数return ()的区别 exit(0):正常运行程序并退出程序: exit(1):非正常运行导致退出程序: return():返回函数,若在主函数 ...
- 在ASP.NET项目中的web.config文件里配置数据库连接并在程序代码中获取连接字符串
1.在<connectionStrings> 标签里添加连接 <connectionStrings> <add name="ConnectionName&q ...
- Java代码中特殊注释
Java代码中特殊注释 TODO: + 说明:标识处有功能代码待编写,待实现的功能在说明中会简略说明. FIXME: + 说明:标识处代码需要修正,甚至代码是错误的,不能工作,需要修复,如何修正会在说 ...
- IDEA插件:快速删除Java代码中的注释
背景 有时,我们需要删除Java源代码中的注释.目前有不少方法,比如: 实现状态机.该方式较为通用,适用于多种语言(取决于状态机支持的注释符号). 正则匹配.该方式容易误判,尤其是容易误删字符串. ...
- 【我的Android进阶之旅】Android 源代码中的Java代码中//$NON-NLS-1$ 注释是什么意思?
1.背景 最近在负责公司基础业务和移动基础设施的开发工作,正在负责Lint代码静态检查工作.因此编写了自定义的Lint规则,在编写自定义的Lint规则前,当然是需要去把Google的关于Lint检测的 ...
- javadoc 抽出代码中的注释
背景: 在已经有的项目里面利用javadoc来抽出代码中每个类,每个方法的注释部分,形成一个文档. 方法1 利用eslipse来实现 之后会在指定的目录下生成html文档 方法2 利用命令来执行 先把 ...
- PHP 之去除代码中的注释
测试文件代码如下: <?php /** * Created by PhpStorm. * User: Yang * Date: 2019/10/16 * Time: 10:25 */ // 计算 ...
- C#程序代码中常用的快捷键
C#中的快捷键,可以更方便的编写代码 //CTRL + SHIFT + B 生成解决方案 //CTRL + F7 生成编译 //CTRL + O 打开文件 //CTRL + SHIFT + O 打开项 ...
- SAP程序代码中RANGE表的用法禁忌
最近经常有出现以上的SQL代码导致程序DUMP,SAP错误日志如下: 经过检查RANGE表GR_MATNR,当用于WHERE条件是,只限较小的数据量的情况(约100条左右): 若为大数据量 ...
随机推荐
- hdu 4582 树状DP
思路:首先声明我是参考:http://blog.csdn.net/frog1902/article/details/9921845这位大牛的博客的. 他说的已经很详尽,但我还是要补充几点. 看完他的解 ...
- poj 1469 二分图最大匹配
就是最简单的最大匹配,没的说 #include<iostream> #include<cstdio> #include<cstring> #include<a ...
- Servlet & JSP - getParameter 与 request.getAttribute 的区别
getParameter 方法获取的是表单或 URL 的请求参数.参数是从 Web 客户端传递至 Web 服务端.例如有如下的 servlet: @WebServlet(name = "he ...
- Sql Server关于text类型的替换
UPDATE Store SET Body=replace(convert(varchar(8000),Body),'http://120.89.46.68:8007','')
- Android应用源码基于安卓的校园二手交易系统客户端+服务端+数据库
该源码是校园二手交易系统应用带服务端,也是一个基于安卓和javaweb的校园二手交易系统,包括整套安卓客户端.javaweb服务端.mysql数据库,可以进行基本的列表显示帖子.显示帖子详情.用户注册 ...
- SQL Server 中WITH (NOLOCK)浅析(转潇湘隐者)
博文出处:http://www.cnblogs.com/kerrycode/p/3946268.html 概念介绍 开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其 ...
- C#程序员整理的Unity 3D笔记(十五):Unity 3D UI控件至尊–NGUI
目前,UGUI问世不过半年(其随着Unity 4.6发布问世),而市面上商用的产品,UI控件的至尊为NGUI:影响力和广度(可搜索公司招聘Unity 3D,常常能看到对NGUI关键词). NGUI虽然 ...
- 第四十三篇、利用NSProxy解决NSTimer内存泄漏问题
问题描述: 用NSTimer来实现每隔一定时间执行制定的任务,例如最常见的广告轮播图.如果我们在 timerWithTimeInterval:1 target:self 中指定target为当前控制器 ...
- MacBook Pro 的照相机在哪?
用于拍照 用于录制视频
- OC2_点语法(属性关键字)
// // Dog.h // OC2_点语法(属性关键字) // // Created by zhangxueming on 15/6/16. // Copyright (c) 2015年 zhang ...