关于C语言字符串函数的思考计算机等级考试

文章作者 100test 发表时间 2009:07:09 23:00:31
来源 100Test.Com百考试题网


  C语言并不是一种很方便的语言,它的字符串就是一例。按照C语言的定义,“字符串就是一段内存空间,里面包含ASCII字符,并且,以”“结尾,总共能存放n-1个字符。”按照这个描述,字符串处理确实很麻烦,还很容易出错。
  为了方便用户,C语言标准库向用户提供了一些字符串函数,如字符串拷贝、构造、清空等函数,在一定程度上方便了用户的使用。但是,我无意中发现,这些函数还是有些隐患的。
  事情很简单,我注意到我写的一些程序,老是有内存读写错误,但是,经过仔细检查我所有的数据Buffer,以及相关的处理函数,又没有找到什么错误。于是我把怀疑的目光投向我常用的一些字符串处理函数上,如strcpy、sprintf等。在经过几次仔细地跟踪之后,我发现内存错误出自于此。于是,我开始研究如何安全地使用字符串这个话题。
  1.字符串拷贝函数
  1.1 不安全的strcpy
  首先,我写了这样一个测试函数:
  void strcpyTest0()
  {
  int i;
  char szBuf[128];
  for(i=0;i<.128;i ) szBuf[i]=’*’;
  szBuf[127]=’’;  //构造一个全部是*的字符串
  char szBuf2[256];
  for(i=0;i<.256;i ) szBuf2[i]=’#’;
  szBuf2[255]=’’;   //构造一个全部是#的字符串
  strcpy(szBuf,szBuf2);
  printf("%sn",szBuf);
  }
  很简单,把一个字符串拷贝到另外一个空间,但是,很不幸,源字符串比目标地址要长,因此,程序很悲惨地死去了。
  1.2 还是不安全的strncpy
  通过上例,我发现我需要在拷贝时多输入一个参数,来标明目的地址有多长,检查C语言的库函数说明,有一个strncpy可以达到这个目的,这个函数的原型如下:
  char *strncpy( char *strDest, const char *strSource, size_t count );
  好了,这下我们的问题解决了,我写出了如下代码:
  void strcpyTest1()
  {
  int i.
  char szBuf[128].
  for(i=0.i<.128.i ) szBuf[i]=’*’.
  szBuf[127]=’’.
  char szBuf2[256].
  for(i=0.i<.256.i ) szBuf2[i]=’#’.
  szBuf2[255]=’’.
  strncpy(szBuf,szBuf2,128).
  printf("%sn",szBuf).
  }
  一切都显得很好,但是,当我输出结果的时候,发现了问题,字符串后面有时会跟几个奇怪的字符,好像没有用“”结束,于是我把上面的拷贝语句改成“strncpy(szBuf,szBuf2,8);”,只拷贝8个字符,问题出现了,程序输出如下:
########***********************************************************************************************************************
  果然,当请求的目标地址空间比源字符串空间要小的时候,strncpy将不再用“”来结束字符串。巨大的隐患。
  1.3 安全地字符串拷贝函数
  我仔细想了想,我认为我需要如下一个字符串拷贝函数:
  1、允许用一个整数界定目标地址空间尺寸。
  2、当目标地址空间nD小于源字符串长度nS时,应该只拷贝nD个字节。
  3、任何情况下,目标地址空间均应该以“”结束,保持一个合法的字符串身份。因此,得到的字符串最大长度为nD-1.
  于是,我写了这么一个字符串拷贝函数:
  void xg_strncpy1(char *pD, char *pS,int nDestSize)
  {
  memcpy(pD,pS,nDestSize).
  *(pD nDestSize-1)=’’.
  }
  很EASY是不,将这个拷贝函数代入上面的例子,只输出7个“#”, 结果正确。
  1.4 内存读错误的思考
  本来以为可以就此打住了,不过,没多久,我就发现一个奇怪的现象,这个函数在VC的Debug模式下有错误,但是Release模式下却一切正常。
  我奇怪了很久,终于有一天我忍不住了,决定解决这个问题,我把上面的memcpy用自己的一个复制循环代替,单步跟踪,想看看究竟怎么回事?
  原因找到了,我希望拷贝一个256字节长的字符串,但是,拷贝到第33字节时出错,检查程序,发现我的源字符串空间只有32 Bytes,原来,我上面的代码只是防止了内存写出界,但没有针对读出界进行检查,在VC的Debug模式下,内存读出界也是一种非法错误,因此被报错。
  知道了原因,解决就很简单了,我把上面的拷贝函数改成如下形状:
  void xg_strncpy2(char *pD, char *pS,int nDestSize)
  {
  int nLen=strlen(pS) 1.
  if(nLen>.nDestSize) nLen=nDestSize.
  memcpy(pD,pS,nLen).
  *(pD nLen-1)=’’.
  }
  一切OK.

相关文章


关于C语言字符串函数的思考计算机等级考试
澳大利亚华人论坛
考好网
日本华人论坛
华人移民留学论坛
英国华人论坛