c语言取消注释,去掉C/C++程序代码中的注释

本文介绍了一个C语言函数,用于去除C/C++程序中的注释,包括单行注释(//)、多行注释(/*...*/)以及字符串中的注释。函数通过遍历代码并使用switch-case语句进行处理,考虑了字符串和注释的嵌套关系,确保不破坏代码的结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面的代码比较复杂一些,请分段思考。

另外要联系思考:在""和''中间的双斜杠中第一个斜杠在"和'后面判断就跳过了,第二次是让case语句来处理,然而case的第一个if就是依靠前面是否已经探测到过"或',探测到了的话,要跳过。

还要考虑到非注释中的单引号''中间只能有一个/,否则C语句非法。

===============================================================================

/********************************************************

功能:去除C/C++中的注释

输入:指向C/C++程序代码的指针

来源:程序员面试宝典第45页

注意:①要考虑到""或' '中的//和/*,//和/*的嵌套关系。

②单引号、双引号中的//是两个字符,第一个字符在单引号的case语句中跳过了,

第二个字符则在case '/'中处理。

*********************************************************/

#include #include #include #include #include #include

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) /*当指针没有到达文件末尾   \r///***///*/,故意带这些不规范的符号的,因为调试就用这个代码,哈哈。*/

{

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; //len = p-sq_start; p++;

if (len == 2 && *(sq_start+1) == '\\') //这个是将遇到'//'的情况排除

{

continue; //忽略单引号中单独存在//的时候,即不再往下处理。

}

sq_start = NULL; //否则将sq_start置位为NULL,C语言中单引号内最多只可能有一个字符而已,不要思考复杂了哦len == 0 或 1 或 2

}

/*******************************以上是没有遇到过双引号或//或/*的时候*******************************/

break;

}

case '\"': /*处理双引号,其实只也是为了排除"//"的情况,否则不需要有这个情况判断,注意第二个斜杠不在这里判断*/

{

if (sq_start || lc_start || bc_start) //当遇到过单引号、//或/*的时候,则不需要处理

{

p++;

continue;

}

/*****************以下是没有遇到过单引号或//或/*的时候*****************/

if (dq_start == NULL) /*如果没有遇到过双引号*/

{

dq_start = p++; //标记遇到了双引号

}

else if (*((p++) -1) =='\\') //双引号中的/也不需要处理。

{

continue;

}

printf("hello // world?? /**/"); //这种情况呢?怎么办?——这个情况会在遇到/是的第一个if语句被跳过

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

{ //其它情况,再去判断下一个是什么符号——注意:C程序可以有其他情况吗?这句话我认为永远不可能执行到。

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; /*这两行本程序每次case后面都紧跟,就是忽略过的意思*/

}

c = *(p - 1);

//如果遇到过双斜杠,清空双斜杠本身和到n前面的那个字符,p指向下一个字符,/r是回车符(光标退回到最前面),要忽略。有这个情况吗???

memset(lc_start, ' ', (c == '\r'? ((p++) -1) : p++) - lc_start);

lc_start = NULL;

break;

}

default:

p++;

break;

}

/****************************************************

如果遇到双斜杠,这个if语句存在的意义在于万一最后

一行代码是带有双斜杠但没有给换行符\n的,也要清除掉。

不带文件末尾的双斜杠的行尾一定有\n,这不是代码中写的

\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 \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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值