strlen、strcpy、strcat等字符串处理函数的实现

最近参加不少小公司的笔试,都是关于C++开发工程师的岗位,考察的题目比较基础。不少公司都考察了关于字符处理函数的实现,这些看起来很简单,其实需要注意的地方还是很多的。这里给出strlen、strcpy、strcat等函数的实现,以及指出需要注意的地方。

strlen求字符串的实际长度,其函数的原型为:

extern unsigned int strlen(char *s);

其实现如下:

int strlen(char *s)
{
	int n=0;
	while(*s!='\0')
	{
		n++;
		s++;
	}
	return n;
}

int strlen(char *s)
{
	int n=0;
	while(*s++)//’\0’是8个比特位全0的二进制编码,因此可以简化
		n++;
	return n;
}

int strlen(char *s)
{
	char *p=s;
	while(*p++);
	return p-s;
}

其实上述实现都有个问题就是没有做指针的有效性检查,下面的几个版本纠正了这个问题:

int strlen(const char *str){
	assert(str!=NULL);
	intlen=0;
	while((*str++)!='\0')
		len++;
	return len;
}

int	strlen(const char *str){
	assert(str);
	const char*p=str;
	while(*p++!=NULL);
	return	p-str-1;
}

int strlen(const char *str){
	assert(str);
	if(*str==NULL)
		return 0;
	else
	return (1+strlen(++str));
}
/***strlen-Find the length of a string*@s:The string to be sized*/
size_t strlen(const char *s){
	const char *sc;
	for(sc=s;*sc!='\0';++sc);/*nothing*/
	return sc-s;
}

参考:

http://baike.baidu.com/link?url=mrMiiM1wl8VBJdAXxo_SgApoTBCbl8elssSq93WEyuR_2uew1OHuT2utkKLQBMH2-bl0xKWyAzAzSmHJafD4KJUw3k6CuSNNsKq7pwcQ3wG

strcpy函数实现字符串的复制,关于这个函数,不动脑子的实现是下面几个版本,本人写的时候就是这么写的,呵呵。

void strcpy(char s[],char t[])//数组参数版 
{
	int n=0;
	while((s[n]=t[n])!='\0')
		n++;
}

void strcpy(char *s,char *t)//指针形参版
{
	int n=0;
	while((s[n]=t[n])!='\0')
		n++;
}
void strcpy(char *s,char *t)//指针形参简化版 
{
	while((*s++=*t++));
}

实际上strcpy的函数原型是这样的:

char *strcpy(char* dest, const char *src);

函数返回值为char *类型,返回的是一个地址,这样做的一个好处就是能够支持链式表达式,比如说链式表达式的形式如:int len=strlen(strcpy(strA,strB));

又如:char * strA=strcpy(new char[10],strB);

此外,返回src的原始值也是错误的,主要有以下三点:

其一,源字符串肯定是已知的,返回它没有任何意义。

其二,不能支持形如第二例的表达式。

其三,把const char *作为char *返回,类型不符,编译会报错。

这个函数看似简单,其实关于它的实现有很多需要注意的地方,像指针的有效性检查、源字符串参数用const修饰,防止修改源字符串、内存重叠情况等问题。

下面的实现不考虑内存重叠问题,其典型的实现如下:

/**********************
*C语言标准库函数strcpy的一种典型的工业级的最简实现
*返回值:目标串的地址。
*对于出现异常的情况ANSI-C99标准并未定义,故由实现者决定返回值,通常为NULL。
*参数:des为目标字符串,source为原字符串
*/
 char* strcpy(char* des,const char* source)
 {
 char* r=des;
  assert((des != NULL) && (source != NULL));
 while((*des++ = *source++)!='\0');
 return r;
 }
 /*while((*des++=*source++));的解释:赋值表达式返回左操作数,所以在赋值NULL后,循环停止*/

对此,百度百科上也有详细的说明

http://baike.baidu.com/link?url=OjQ2KCfPJ8JblYyu5PW_V3f9-iB6d4zIEOvVoiIhHnZce_FpNcegKihkzmgCodepfiR4y5J-uaZwIOtiaVYGWq

 内存重叠问题单独拿出来讨论,所谓的内存重叠就是:

char s[10]="hello";

strcpy(s, s+1); //应返回ello

strcpy(s+1, s); //应返回hhello,

但实际会报错,因为dest与src重叠了,把'\0'覆盖了,即在src<=dst<=src+strlen(src)的情况下,就会发生内存重叠问题,针对这个问题给出带有内存重叠检测的strcpy函数实现如下:

char * strcpy(char *dest,const char *src)
{
    assert(dest != NULL && src != NULL);
    char *ret = dest;
    my_memcpy(dest, src, strlen(src)+1);
    return ret;
}
char *my_memcpy(char *dst, const char* src, int cnt)
{
    assert(dst != NULL && src != NULL);
    char *ret = dst; 

    if (dst >= src && dst <= src+cnt-1) //内存重叠,从高地址开始复制
    {
        dst = dst+cnt-1;
        src = src+cnt-1;
        while (cnt--)
            *dst-- = *src--;
    }
    else    //正常情况,从低地址开始复制
    {
        while (cnt--)
            *dst++ = *src++;
    }
    return ret;
}

参考

http://www.cnblogs.com/chenyg32/p/3739564.html

P.S.:

Linux下memcpy的函数实现如下:

void* memcpy(void *dest,const void *src,size_t count)
{
    assert(dest!=NULL && src!=NULL);
    char* tmp=dest;
    const char* s=src;
    for(size_t i=0;i<count;i++)
{
    tmp[i]=s[i];
}
    return dest;
}

strcpy和memcpy主要有以下3方面的区别。

1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。

2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。

3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy

 

函数strcat实现两个字符串的连接,其函数原型如下:

extern char *strcat(char *dest,char *src);

其实现如下:

//将源字符串加const,表明其为输入参数
char* strcat(char* strDest , const char* strSrc)
{
    //后文return address,故不能放在assert断言之后声明address
    char* address=strDest;
    assert( (strDest!=NULL)&&(strSrc!=NULL) );//对源地址和目的地址加非0断言
    while(*strDest)//是while(*strDest!=’\0’)的简化形式
    {
        //若使用while(*strDest++),则会出错,因为循环结束后strDest还会执行一次++,
        //那么strDest将指向'\0'的下一个位置。/所以要在循环体内++;因为要使*strDest最后指
        //向该字符串的结束标志’\0’。
        strDest++;
    }
 
    while(*strDest++=*strSrc++)
    {
        NULL;//该循环条件内可以用++,
    }//此处可以加语句*strDest=’\0’;无必要
    return address;//为了实现链式操作,将目的地址返回
}
char *mystrcat(char *dest,const char *src)
{
	char *p=dest;
	while(*dest!='\0') dest++;
	while(*src!='\0') *dest++=*src++;
	*dest='\0';
	return p;//dest现在指向拼接后的最后一位字符,在这里返回dst,会出现错误
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值