分享

要求一段函数,可以消除代码中的注释,而保留其他部分

 戴维图书馆 2016-03-13

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <io.h>
#include <process.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) /*当指针没有到达文件末尾   \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 filepath[260];
 char buf[102400];
 gets(filepath);
 
 fd = open(filepath, O_RDONLY); /*只读打开*/
 if (fd == -1)
 {
  return -1;
 }
 
 n = read(fd, buf, sizeof(buf));
 if (n == -1 || n == 0)
 {
  close(fd);
  return -1;
 }
 printf("After Delete:\n-----------------------\n");
 remove_comment(buf, n);
 *(buf + n) = '\0';
 printf("%s", buf);
 close(fd);
 
 return 0;
}

 

追问:
include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <io.h>
#include <process.h>这些我们没用过啊,包含了哪些函数啊?
回答:

#include <io.h>
包含:open(),read(),close();只要是流处理。。

 

#include <process.h>这个头文件我删掉了响应的函数,没用到现在。可以去掉这个头文件。。

 

#include <string.h>这个主要是字符串处理使用的头文件,教科书上经常看见吧,如gets(),strcmp等。。

#include <fcntl.h> fcntl.h定义了很多宏和open,fcntl函数原型 。。我里面用到O_RDONLY这个宏。。


 

追问:
可是我们没有学宏,能不能不用宏呢?麻烦了!
回答:

可以,把

 fd = open(filepath, O_RDONLY); 改成

 fd = open(filepath, 0x0000); /*只读打开*/

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多