C语言字符串与指针(4)

2019-03-16 14:44

printf(\ }

一切都显得很好,但是,当我输出结果的时候,发现了问题,字符串后面有时会跟几个奇怪的字符,好像没有用”\\0”结束,于是我把上面的拷贝语句改成“strncpy(szBuf,szBuf2,8);”,只拷贝8个字符,问题出现了,程序输出如下:

########***********************************************************************************************************************

果然,当请求的目标地址空间比源字符串空间要小的时候,strncpy将不再用”\\0”来结束字符串。巨大的隐患。

1.3 安全地字符串拷贝函数

我仔细想了想,我认为我需要如下一个字符串拷贝函数:

1、 允许用一个整数界定目标地址空间尺寸。

2、 当目标地址空间nD小于源字符串长度nS时,应该只拷贝nD个字节。

3、 任何情况下,目标地址空间均应该以”\\0”结束,保持一个合法的字符串身份。因此,得到的字符串最大长度为nD-1。

于是,我写了这么一个字符串拷贝函数:

void xg_strncpy1(char *pD, char *pS,int nDestSize) {

memcpy(pD,pS,nDestSize);

*(pD+nDestSize-1)='\\0'; }

很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)='\\0'; }

一切OK。

2 字符串构造函数 2.1 不安全的sprintf

如同上例,我在修改拷贝函数的同时,我也想到了另外一个我常用的字符串构造函数sprintf,显然,这个函数没有界定目标地址空间的尺寸,也是不安全的,下面的代码将会造成崩溃:

void sprintfTest0() {

int i;

char szBuf[128];

for(i=0;i<128;i++) szBuf[i]='*';

szBuf[127]='\\0';

char szBuf2[256];

for(i=0;i<256;i++) szBuf2[i]='#';

szBuf2[255]='\\0';

sprintf(szBuf,szBuf2);

printf(\ }

2.2 还是不安全的_snprintf

查阅库函数手册,找到这么一个函数_snprintf,其函数原型如下:

int _snprintf( char *buffer, size_t count, const char *format [, argument] ... );

这个函数允许界定目标地址尺寸,但是,由于研究拷贝函数的经验,我怀疑它也有strncpy相同的问题,因此,我写了这么一段代码测试:

void sprintfTest1()

{

int i;

char szBuf[128];

for(i=0;i<128;i++) szBuf[i]='*';

szBuf[127]='\\0';

char szBuf2[256];

for(i=0;i<256;i++) szBuf2[i]='#';

szBuf2[255]='\\0';

_snprintf(szBuf,8,szBuf2);

printf(\

}

果然,程序输出如下:

########***********************************************************************************************************************

同样的错误,没有用”\\0”结束,我必须另外想方法。

另外,还发现了另外一个不足,就是这个时候,_snprintf函数返回-1,不再返回打印的字符数,那么,我们如果使用如下代码将会造成逻辑错误,甚至可能崩溃:

char szBuf[256];

int nCount=0;

while(1) //这里表示循环构造 {

nCount+=_snprintf(szBuf+nCount,256-nCount,”... ...”); //多个字符串构造成一个字符串 }

注意,代码利用_snprintf返回的值,来确定下一个起始点,这很常用,但是,当_snprintf返回-1的时候,有可能会写到*(szBuf-1)的位置上,典型的内存写出界。

2.3 安全地字符串构造函数

经过仔细思考,我构造了如下一个函数:

int xg_printf(char* szBuf,int nDestSize,char *szFormat, ...)

{

int nListCount=0;

va_list pArgList;

va_start (pArgList,szFormat);

nListCount+=_vsnprintf(szBuf+nListCount,

nDestSize-nListCount,szFormat,pArgList);

va_end(pArgList);

*(szBuf+nDestSize-1)='\\0';

return strlen(szBuf); }

注意,这里我采用了变参函数设计,为的是和sprintf一样方便,另外,最后一个return也非常重要,因为很多场合,我们需要知道究竟打印了多少字符。将这段函数代入上面的例子后一切正常。

总结:C语言字符串库函数可能是出于提高性能目的,在一旦条件不够的时候,往往直接返回,忘了采用”\\0”结束字符串。这会造成下一次读取字符串时,数据边界不可控。格式化打印函数,返回值设计不合理,不永远是一个正整数,会造成逻辑隐患。因此,建议大家有兴趣可以参考一下我提供的两个函数。

另外,以上仅为我个人测试之作,限于本人水平所限,肯定还有没考虑到的地方,欢迎大家展开讨论。如果大家需要上面的源代码,请和我联系。

目前,在IT职场上,甚至在整个社会上,普遍存在一种现象,就是刚刚毕业的大学生,不好找工作。究其原因,我们很多人在大学中,虽然学到了很好知识,但是缺乏运用知识的技能,无法满足企业用人的要求,导致就业困难,很多人因此甚至“回炉重造”,以参加各种培训班来弥补这种经验上的缺失,以期尽快找到工作,获得社会的认可。这究竟是广大学生的学习能力出了问题,还是大学的教育出了问题呢?

另外,很多年轻的朋友即使顺利进入到企业中,也会由于经验的缺失,无法快速融入企业商业化开发的氛围,尽管大多数年轻的程序员已经很努力地在学习和工作,但做出来的产品就是无法满足市场的需求,这令他们很苦恼,用他们的企业也很苦恼,这究竟又是怎么一回事呢?

还有个问题,程序员作为一种创造性极强的社会职业,已经获得了大家的认可,但是,大家也几乎公认,程序员是一门非常辛苦的工作。在商业公司中,由于市场竞争的压力,程


C语言字符串与指针(4).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:SNCR+SCR方案 - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: