C/C++学习笔记:字符串库函数

1  strcpy 的函数原型:

char *strcpy(char *strDest, const char*strSrc)     //其中 strDest 是目的字符串,strSrc 是源字符串

// 入门级
char *strcpy(char *strDest, const char *strSrc)
{
	if (NULL == strDest || NULL == strSrc)
	{
		return NULL;
	}
	if ( strDest == strSrc )
	{
		return strDest;
	}

	char *tmpPtr = strDest;
	while('\0' != *strSrc )
	{
             *(strDest++) = *(strSrc++);	 //自动将原字符串的字符依次赋值给strDest
	}                                        //*p++等价于*(p++),而(*p)++是取p所指向地址的值,然后再将这个值+1

	*strDest = '\0';  //拷贝结束标志 '\0'
	return tmpPtr;
}

//工业级
char *strcpy(char *strDest, const char *strSrc)  //使用const来约束strSrc,提高程序的健壮性。
{											      //如果函数体内的语句试图改动strSrc的内容,编译器将指出错误
	assert((strDest != NULL)&&(strSrc !=NULL));	 
	//使用断言来检验输入参数的有效性,如果没有对传入参数strDest和strSrc进行检查,一但它们中有一个为NULL,立死!
	//assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回false,则终止程序执行。

    char *tmp = strDest;
	while ((*strDest++ = *strSrc++) != '\0')
	{
		;//或是 NULL;	 //字符串拷贝的结束标志 '\0', 在while循环中,自动将原字符串的字符依次赋值给strDest,  
		                 //while循环结束时已将源字符串的结束标志赋值过去,while循环内部是空操作
	}
	return tmp;
}

2 strcat函数原型:

char *strcat(char *strDest, const char *strSrc)

char *strcat(char *strDest, const char *strSrc) //将源字符串加const,表明其为输入参数
{
	char *address = strDest; //该语句若放在assert之后,编译出错
	assert((strDest != NULL) && (strSrc != NULL)); //对源地址和目的地址加非0断言
	while(*strDest) //是while(*strDest!=’\0’)的简化形式
	{ 
		strDest ++; 
		//若使用while(*strDest++),则会出错,因为循环结束后strDest还会执行一次++,那么strDest
		//将指向'\0'的下一个位置。//所以要在循环体内++;因为要是*strDest最后指向该字符串的结束标志’\0’。
	} 
	while(*strDest++ = *strSrc++)
    { 
		;//NULL;
	}
	return address;
}

char *strcat(char *strDest, const char *strSrc) //将源字符串加const,表明其为输入参数
{
	char *address = strDest; //该语句若放在assert之后,编译出错
	assert((strDest != NULL) && (strSrc != NULL)); //对源地址和目的地址加非0断言
	while(*strDest) //是while(*strDest!=’\0’)的简化形式
	{ 
		strDest++; 
		//若使用while(*strDest++),则会出错,因为循环结束后strDest还会执行一次++,那么strDest
		//将指向'\0'的下一个位置。//所以要在循环体内++;因为要是*strDest最后指向该字符串的结束标志’\0’。
	} 
	while(*strSrc)
	{
		*strDest = *strSrc;	 //不能用strDest=strSrc;	
		 strDest ++;          //这样改变指针指向,断开了形参与实参之间的联系,实参的值不会受到影响
		 strSrc ++;
	}
	return address;
}

3 strcmp函数原型:

int strcmp(const char *str1, const char *str2)

//源代码
int strcmp(const char *str1, const char *str2)
{
	assert( ('\0' != *str1) && ('\0' != *str2));
	while ( *str1 && *str2 && (*str1 == *str2))
	{
		str1 ++;
		str2 ++;
	}
	return *str1 - *str2;
}

//百度百科的源代码
int strcmp(const char*str1,const char*str2)
{
	/*不可用while(*str1++==*str2++)来比较,当不相等时仍会执行一次++,
	 * return返回的比较值实际上是下一个字符。应将++放到循环体中进行。*/
	while(*str1==*str2)
	{
		if('\0' == *str1)
		{
			return 0;
		}
		str1++;
		str2++;
	}
	return*str1-*str2;
}

4 strlen函数原型:

int strlen(const char *str)

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

//不允许调用库函数,也不允许使用任何全局或局部变量编写
//int my_strlen (char *strDest)
int my_strlen( const char* strDest )
{
    assert(NULL != strDest);
    if ('\0' == *strDest)
    {
        return 0;
    }
    else
    {
        return (1 + my_strlen(++strDest));
    }
}


int my_strlen( const char* strDest )
{
    assert(NULL != strDest);
    return ('\0' != *strDest)?(1+my_strlen(strDest+1)):0;
}


5 memcpy函数原型:

void *memcpy(void *dst, const void *src, size_t count)

void *memcpy(void *dst, const void *src, size_t count)
{
	char *dp = (char*) dst;
	char *sp = (char*) src;
	assert( (0 != src) && (0 != dst) && (count > 0) );
	while ( count -- )
	{
		*( dp ++ ) = *( sp ++ );
	}
	return dst;
}

//另外一种实现
void * memcpy(char *strDest, const char *strSrc, int count)
{
	if(strDest == NULL || strSrc == NULL || count <= 0) 
	{
		return NULL;
	}
	unsigned char *tempDest;
	unsigned char *tempSrc;
	tempDest = (unsigned char *)tempDest;
	tempSrc = (unsigned char *)tempSrc;
	while( count-- )
	{
		*tempDest = *tempSrc;
		tempDest++;
		tempSrc++;
	}
	return strDest;
}

附:strcpy和memcpy主要有以下3方面的区别:
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。

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

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


6  memmove函数原型:

void *  memmove( void * dst,const void * src,size_t count)

// (1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
// (2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
// (3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝

void *  memmove( void * dst,const void * src,size_t count)
{
	void * ret = dst;
	if (dst <= src || (char *)dst >= ((char *)src + count))
	{    // 若dst和src区域没有重叠,则从起始处开始逐一拷贝
		while (count--)
		{
			*(char *)dst = *(char *)src;
			dst = (char *)dst + 1;
			src = (char *)src + 1;
		}
	}
	else
	{ // 若dst和src 区域交叉,则从尾部开始向起始位置拷贝,这样可以避免数据冲突
		dst = (char *)dst + count - 1;
		src = (char *)src + count - 1;
		while (count--)
		{
			*(char *)dst = *(char *)src;
			dst = (char *)dst - 1;
			src = (char *)src - 1;
		}
	}
	return(ret);
}

void* memmove(void* dest, const void* src, size_t n)
{
	char*     d  = (char*) dest;
	const char*  s = (const char*) src;

	if (s>d) 
	{
		// start at beginning of s
		while (n--)
			*d++ = *s++;
	}
	else if (s<d)
	{
		// start at end of s
		d = d+n-1;
		s = s+n-1;

		while (n--)
			*d-- = *s--;
	}
	return dest;
}
// 示意图  
// (1)内存低端 <-----s-----> <-----d-----> 内存高端 start at end of s
// (2)内存低端 <-----s--<==>--d----->      内存高端 start at end of s
// (3)内存低端 <-----sd----->              内存高端 do nothing
// (4)内存低端 <-----d--<==>--s----->      内存高端 start at beginning of s
// (5)内存低端 <-----d-----> <-----s-----> 内存高端 start at beginning of s


附:

memcpy与memmove的目的都是将N个字节的源内存地址的内容拷贝到目标内存地址中。

当src和dst区域没有重叠时,两个函数是完全一样的。木有重叠的条件是: dst <= src || (char *)dst >= ((char *)src + count 。否则,memcpy是不能正常工作的,memmove是可以正常工作的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值