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是可以正常工作的