strcpy()、strlen()、memcpy()、memmove()、memset()的实现
strcpy(), 字符串拷贝.
char *strcpy(char *strDest, const char *strSrc)
{
assert((strDest!=NULL) && (strSrc !=NULL));
char *address = strDest;
while( (*strDest++ = * strSrc++) != '\0')
NULL ;
return address ;
}
strlen,
int strlen( const char *str)
{
assert(str != NULL);
int len = 0;
while((*str++) != '\0')
len++;
return len;
}
int strlen( const char *str)
{
assert(str != NULL);
const char *p = str;
while((*p++) != '\0');
return p - str - 1;
}
int strlen( const char* str)
{
if (str[0] == '\0')
return 0;
else
return strlen((char *)(&str[0]+1))+1;
}
memcpy, 拷贝不重叠的内存块
void *memcpy(void* pvTo, void* pvFrom, size_t count)
{
assert(pvTo != NULL && pvFrom != NULL);
byte* pbTo = (byte*)pvTo;
byte* pbFrom = (byte*)pvFrom;
assert(pbTo>=pbFrom+count || pbFrom>=pbTo+count);
while(count-- > )
*pbTo++ == *pbFrom++;
return pvTo;
}
void* memmove(void *dest, const void *src,size_t count)
{
if (count == ) return ;
if (dest == NULL) return ;
if (src == NULL) return ;
char *psrc = (char*)src;
char *pdest = (char*)dest;
if((pdest <= psrc) || (pdest >= psrc +count))
{
while (count--)
*pdest++ = *psrc++;
}
else
{
pdest += count - 1;
psrc += count - 1;
while (count--)
*pdest-- = *psrc--;
}
return dest;
}
memset:把buffer所指内存区域的前count个字节设置成字符c
void * memset(void* buffer, int c, int count)
{
char* pvTo=(char*)buffer;
assert(buffer != NULL);
while(count-- > )
*pvTo++=(char)c;
return buffer;
}
分析:
memmove、memcpy和memccpy三个函数都是内存的拷贝,从一个缓冲区拷贝到另一个缓冲区。
memmove(void *dest,void*src,int count)
memcpy(void *dest,void *src,int count)
memccpy(void*dest,void*src,int ch,int count)
表头文件: #include <string.h>
定义函数: void *memcpy(void *dest, const void *src, size_t n)
函数说明: memcpy()用来拷贝src所指的内存内容前n个字节到dest所指的内存地址上。与strcpy()不同的是,memcpy()会完整的复制n个字节,不会因为遇到字符串结束'\0'而结束
返回值: 返回指向dest的指针
表头文件: #include <string.h>
定义函数: void *memccpy(void *dest, const void *src, int c, size_t n);
函数说明: memccpy()用来拷贝src所指的内存内容前n个字节到dest所指的地址上。与memcpy()不同的是,memccpy()如果在src中遇到某个特定值(int c)立即停止复制。
返回值: 返回指向dest中值为c的下一个字节指针。返回值为0表示在src所指内存前n个字节中没有值为c的字节。
表头文件: #include <string.h>
定义函数: void *memmove(void *dest, const void *src, size_t n);
函数说明:memmove()是从一个缓冲区移动到另一个缓冲区中。
返回值: 返回指向dest指针。
当dest <= src-count 或dest >= src+count时,以上三个函数均不会产生覆盖问题,即源数据不会被更改。
若不在以上范围内,则源数据会被更改。 不妨用个小程序来测一下:
# include <string.h>
_____________________________
1.//整数转换成字符串itoa函数的实现
#include "stdafx.h"
#include <iostream>
using namespace std;
void itoaTest(int num,char str[] )
{
int sign = num,i = 0,j = 0;
char temp[11];
if(sign<0)//判断是否是一个负数
{
num = -num;
};
do
{
temp[i] = num%10+'0';
num/=10;
i++;
}while(num>0);
if(sign<0)
{
temp[i++] = '-';//对于负数,要加以负号
}
temp[i] = '\0';
i--;
while(i>=0)//反向操作
{
str[j] = temp[i];
j++;
i--;
}
str[j] = '\0';
}
2. //字符串转换成整数atoi函数的实现
int atoiTest(char s[])
{
int i = 0,sum = 0,sign; //输入的数前面可能还有空格或制表符应加判断
while(' '==s[i]||'\t'==s[i])
{
i++;
}
sign = ('-'==s[i])?-1:1;
if('-'==s[i]||'+'==s[i])
{
i++;
}
while(s[i]!='\0')
{
sum = s[i]-'0'+sum*10;
i++;
}
return sign*sum;
}
3.//字符串拷贝函数
#include "stdafx.h"
#include <assert.h>
#include <string.h>
#include <iostream>
using namespace std;
char *srcpy(char *dest,const char *source)
{
assert((dest!=NULL)&&(source!=NULL));
char *address = dest;
while(*source!='\0')
{
*dest++=*source++;
}
*dest = '\0';
return address;
}
4.//判断输入的是否是一个回文字符串
#include "stdafx.h"
#include <string.h>
#include <iostream>
using namespace std;
//方法一:借助数组
bool isPalindrome(char *input)
{
char s[100];
strcpy(s,input);
int length = strlen(input);
int begin = 0,end = length-1;
while(begin<end)
{
if(s[begin]==s[end])
{
begin++;
end--;
}
else
{
break;
}
}
if(begin<end)
{
return false;
}
else
{
return true;
}
}
//方法二:使用指针
bool isPalindrome2(char *input)
{
if(input==NULL)
return false;
char *begin = input;
char *end = begin+strlen(input)-1;
while(begin<end)
{
if(*begin++!=*end--)
return false;
}
return true;
}
int main(int argc, char* argv[])
{
char *s ="1234554321";
if(isPalindrome(s))
{
cout<<"True"<<endl;
}
else
{
cout<<"Fasle"<<endl;
}
if(isPalindrome2(s))
{
cout<<"True"<<endl;
}
else
{
cout<<"Fasle"<<endl;
}
cin.get();
return 0;
}
5.//不使用库函数,编写函数int strcmp(char *source, char *dest),若相等返回0,否则返回-1
int strcmp(char *source, char *dest)
{
assert(source != NULL && dest != NULL);
while(*source++==*dest++)
{
if(*source=='\0'&&*dest=='\0')
return 0;
}
return -1;
}
——————————————————————————————
一:strcmp,_stricmp
strcmp("ha","he")是可以的。
但是如下代码:
string str1 = "ha";
string str2 = "he";
strcmp(str1, str2);
会产生如下的ERROR:
因为:
1)int strcmp(const char* str1, const char* str2);
这个函数是C标准库的函数,处理的是C风格0结尾字符数组字符串。
C++标准库中的string类有可以直接使用的<,>,<=,>=,==,!=运算符,通常也用不到这个函数
或者说: strcmp()处理的是C风格的字符串。 而你用的是string类,2者是不同的。
但可以通过string成员函数string::c_str()转换成char*类型。象这样调用:strcmp(str1.c_str(), str2.c_str())
int ret = strcmp("aa", "ad"); //-1
int ret = _stricmp("aa", "ad");//-3
int ret = _stricmp("Aa","aD"); //-3
ret = strcmp("ad", "aa"); //1
ret = strcmp("aa", "aa"); //0
ret = _stricmp("aa", "AA"); //0
ret = strcmp("aa", "aad"); //-1
strcmp(s1,s2)与_stricmp(s1,s2)
相同点:处理的都是C格式的字串,如果比较C++格式的string类型字串时,可以使用string.c_str()来转换成C格式的字串再进行比较。
不同点:1)前者区分大小写,后者不区分大小写
2)前者返回-1,0,1,后者返回字串实际差值,即整形数:负数,零,正数
二:strcpy_s&&strcpy的比较
如下所示:
char szBuf[2] = {0};
strcpy_s(szBuf, 2, "12131"); //注意第二个参数是申清空间的大小
strcpy(szBuf, "12131");
上述代码,明显有缓冲区溢出的问题。 使用strcpy_s函数则会抛出一个异常。而使用strcpy函数的结果
则未定,因为它错误地改变了程序中其他部分的内存的数据,可能不会抛出异常但导致程序数据错误,
也可能由于非法内存访问抛出异常。使用新的增强安全的CRT函数有什么好处呢?简单地说,新的函数
加强了对参数合法性的检查以及缓冲区边界的检查,如果发现错误,会返回errno或抛出异常。
老版本的这些CRT函数则没有那么严格的检查与校验,如果错误地传输了参数或者缓冲区溢出,
那么错误并不能被立刻发现,对于定位程序错误也带来更大困难。
//--------------------strcpy,strcpy_s------------------------------------------
//原型:extern char *strcpy(char *dest,char *src);
//功能:把src所指由NULL结束的字符串复制到dest所指的数组中。
//说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,返回指向dest的指针。
//strcpy用法:
// 若源长<目标长 --->OK。
//将源串COPY至目标串(包括结尾符),其它字节保持不变,
//若源长>目标长 --->溢出报错。
//将源串COPY至目标串(包括结尾符),但目标串太短,下标越界而溢出,不正常的字串显然会在导致运行时异常,
//使用原则总结:使用时保证源长<目标长
//strcpy_s用法:
//若源长<目标长 sizeof([min, max])--->OK,但自定义拷贝的字串长度超过目标长度时,会因下标越界而导致运行异常
//若源长>目标长 sizeof任何一方都会发生运行异常,
//(有可能是编译器在copy前会先检查两者长度,
//如果源串较长便会发生告警而退出,因此后续使用sizeof(strlen(strDest)=0)语句已无效)
//使用原则总结: 1,使用时保证:源长<目标长,2,长度不能超出szDest长度,建议使用sizeof(szDest)
#include <iostream>
#include <string>
using namespace std;
#define STRCPY_TEST 0
#define LEN_STR 15
void main()
{
char szDest[10];
char szSrc_shorter[] = "1234";
char szSrc_longer[] ="123456789012";
cout<<"char szDest[10];"<<endl;
cout<<"char szSrc_shorter[] = \"1234\";"<<endl;
cout<<"char szSrc_longer[] = \"123456789012345\";"<<endl;
#if (0 == STRCPY_TEST)
cout<<"\n[OK] strcpy(szDest, szSrc_shorter);\nstrDest[1~15] = ";
strcpy(szDest, szSrc_shorter);
for(int i = 0; i < LEN_STR; i++)
{
cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;
strcpy(szDest, szSrc_longer);
cout<<"\n[NG] strcpy(szDest, szSrc_longer);\nstrDest[1~15] = ";
for(int i = 0; i < LEN_STR; i++)
{
cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;
#else
cout<<"\n[OK] strcpy_s(szDest, sizeof(szSrc_shorter), szSrc_shorter);\nstrDest[1~15] = ";
strcpy_s(szDest, sizeof(szSrc_shorter), szSrc_shorter);
for(int i = 0; i < LEN_STR; i++)
{
cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;
cout<<"[OK] strcpy_s(szDest, sizeof(szDest), szSrc_shorter);\nstrDest[1~15] = ";
strcpy_s(szDest, sizeof(szDest), szSrc_shorter);
for(int i = 0; i < LEN_STR; i++)
{
cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;
cout<<"[NG] strcpy_s(szDest, sizeof(szSrc_longer), szSrc_longer);\nstrDest[1~15] = ";
strcpy_s(szDest, sizeof(szSrc_longer), szSrc_longer);
for(int i = 0; i < LEN_STR; i++)
{
cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;
cout<<"\n[NG] strcpy_s(szDest, sizeof(szDest), szSrc_longer);\nstrDest[1~15] = ";
strcpy_s(szDest, sizeof(szDest), szSrc_longer);
szDest[sizeof(szDest) - 1] = 0;
for(int i = 0; i < LEN_STR; i++)
{
cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;
#endif
}
输出:(NG部分的输出已无意义,可以不看)
(1)STRCPY_TEST==0
char szDest[10];
char szSrc_shorter[] = "1234";
char szSrc_longer[] = "123456789012345";
[OK] strcpy(szDest, szSrc_shorter);
strDest[1~15] = 1, 2, 3, 4, , ? ? ? ? ? ? ? ? ? ?
szDest = 1234
[NG] strcpy(szDest, szSrc_longer);
strDest[1~15] = 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, , ? ?
(2)STR_CPY_TEST<>0
char szDest[10];
char szSrc_shorter[] = "1234";
char szSrc_longer[] = "123456789012345";
[OK] strcpy_s(szDest, sizeof(szSrc_shorter), szSrc_shorter);
strDest[1~15] = 1, 2, 3, 4, , ? ? ? ? ? ? ? ? ? ?
szDest = 1234
[OK] strcpy_s(szDest, sizeof(szDest), szSrc_shorter);
strDest[1~15] = 1, 2, 3, 4, , ? ? ? ? ? ? ? ? ? ?
szDest = 1234
[NG] strcpy_s(szDest, sizeof(szSrc_longer), szSrc_longer);
strDest[1~15] = 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, , ? ?
szDest = 123456789012
[NG] strcpy_s(szDest, sizeof(szDest), szSrc_longer);
strDest[1~15] = 请按任意键继续. . .
//-------------------------------memcpy-------------------------------------
// 原型:extern void *memcpy(void *dest, void *src, unsigned int count);
// 原理:由src所指内存区域复制count个字节到dest所指内存区域。
// 说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。
//strncpy() 是处理的字符串(遇零结束),
//memcpy() 是处理一个缓冲区(void*类型的),
//以字串类型的memcpy用法为例:
//源长<目标长时,第3个参数使用任何一方的size,效果都一样
//源长>目标长时,第3个参数用sizeof(strSrc),会造成下标越界,而使目标串溢出,从而导致运行异常
// 第3个参数用sizeof(strDest), 末尾字符(\0)没有被COPY,输出字串会有乱码,
// 但不会运行异常,如果不考虑完整性,可以使用strDest[sizeof(strDest)-1]=0截取前半部
//使用原则总结:1)保证源长<目标长;2)第3个参数推荐使用sizeof(strDest) 另外如果字串是指针要考虑一下sizeof的副作用
#include <iostream>
#include <string>
using namespace std;
void main()
{
char szSrc_shorter[] = "Good";
char szSrc_longer[] = "Have a Good Day!";
char szDest[10];
cout<<"char szSrc_shorter[] = \"Good\";"<<endl;
cout<<"char szSrc_longer[] = \"Have a Good Day!\";"<<endl;
cout<<"char szDest[10];"<<endl<<endl;
memcpy(szDest, szSrc_shorter, sizeof(szSrc_shorter));//<=>
//memcpy(szDest, szSrc_shorter, sizeof(szDest));
cout<<"[OK] memcpy(szDest, szSrc_shorter, sizeof(szSrc_shorter));";
cout<<"<=>\n[OK] memcpy(szDest, szSrc_shorter, sizeof(szDest));\nszDest[0~20] = \n";
for (int i = 0; i < 20; i++)
cout<<szDest[i]<<", ";
cout<<endl<<"szDest = "<<szDest<<endl;
memcpy(szDest, szSrc_longer, sizeof(szDest));
cout<<"\n[OK] memcpy(szDest, szSrc_longer, sizeof(szDest));\nszDest[sizeof(szDest) - 1] = 0; \nszDest[0~20] = \n";
szDest[sizeof(szDest) - 1] = 0;
for (int i = 0; i < 20; i++)
cout<<szDest[i]<<", ";
cout<<endl<<"szDest = "<<szDest<<endl;
memcpy(szDest, szSrc_longer, sizeof(szSrc_longer));
cout<<"\n[NG] memcpy(szDest, szSrc_longer, sizeof(szSrc_longer));\nszDest[sizeof(szDest) - 1] = 0; \nszDest[0~20] = \n";
szDest[sizeof(szDest) - 1] = 0;
for (int i = 0; i < 20; i++)
cout<<szDest[i]<<", ";
cout<<endl<<"szDest = "<<szDest<<endl;
}
输出:(NG部分的输出没有意义,可以不看):
char szSrc_shorter[] = "Good";
char szSrc_longer[] = "Have a Good Day!";
char szDest[10];
[OK] memcpy(szDest, szSrc_shorter, sizeof(szSrc_shorter));<=>
[OK] memcpy(szDest, szSrc_shorter, sizeof(szDest));
szDest[0~20] =
G, o, o, d, , ?.....?(15个?)
szDest = Good
[OK] memcpy(szDest, szSrc_longer, sizeof(szDest));
szDest[sizeof(szDest) - 1] = 0;
szDest[0~20] =
H, a, v, e, , a, , G, o, , ? ...?(10个?)
szDest = Have a Go
[NG] memcpy(szDest, szSrc_longer, sizeof(szSrc_longer));
szDest[sizeof(szDest) - 1] = 0;
szDest[0~20] =
H, a, v, e, , a, , G, o, , d, , D, a, y, !, , ? ? ?
szDest = Have a Go
来源:oschina
链接:https://my.oschina.net/u/66133/blog/28721