atoi,itoa
strcpy,strstr,strcmp
memcpy,memove,memset
1.itoa
注意:字符串倒置
char* itoa(int a,char* string)
{
int i=0,j=0;
char temp[10],string[10]; while(a) {
i=a%10+'0'; temp[j++]=i; a=a/10; } i=0; j--; while(j>=0) string[i++]=temp[j--]; string[i]='\0';
return string;
}
/* 实现itoa函数的源代码 */char *myitoa(int num,char *str,int radix){/* 索引表 */char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";unsigned unum; /* 中间变量 */int i=0,j,k;/* 确定unum的值 */if(radix==10&&num<0) /* 十进制负数 */{unum=(unsigned)-num;str[i++]='-';}else unum=(unsigned)num; /* 其他情况 *//* 逆序 */do{str[i++]=index[unum%(unsigned)radix];unum/=radix;}while(unum);str[i]='\0';/* 转换 */if(str[0]=='-') k=1; /* 十进制负数 */else k=0;/* 将原来的“/2”改为“/2.0”,保证当num在16~255之间,radix等于16时,也能得到正确结果 */char temp;for(j=k;j<=(i-k-1)/2.0;j++){temp=str[j];str[j]=str[i-j-1];str[i-j-1]=temp;}return str;}
2.atoi
注意:判断正负
int atoi(char* s)
{
assert(s!=NULL);
int i,num,flag=0;//正负数标记
if(s[0]=='-') flag=-1;
i=(flag==0)?0:1;
for(;i<strlen(s);i++)
num=num*10+s[i]-'0';
return (flag==0)?num:(-num);
}
3.strcpy
原型
char* strcpy(char *dest,const char *src);
实现
char* strcpy(char *dest,const char *src)
{
assert( (dest != NULL) && (src != NULL) ); //写上
char *temp=dest;
while( (*dest=*src)!='\0')//赋值加判断写在一起,这样写简洁
{
dest++;
src++;
}
/*
while( (*dest++=*src++)!='\0'); //更加简洁
*/
return temp;
}
注意:
错误的做法:
1.不检查指针的有效性,说明答题者不注重代码的健壮性。
2.return new string("Invalid argument(s)");,说明答题者根本不知道返回值的用途,并且他对内存泄漏也没有警惕心。从函数中返回函数体内分配的内存是十分危险的做法,他把释放内存的义务抛给不知情的调用者,绝大多数情况下,调用者不会释放内存,这导致内存泄漏。
3.循环写成while(*strSrc!='\0') *strDest++=*strSrc++;,说明答题者对边界条件的检查不力。循环体结束后,strDest字符串的末尾没有正确地加上'\0'。
4.strstr
原型:
char *strstr(const char* s1,const char* s2)
{
int len=strlen(s2);
if(len == 0) return (char*)s1;
for(;*s1;++s1)//这里其实就是for(s1=s1;*s1!='\0';++s1)
{
if(*s1==*s2 && strncmp(s1,s2,len))
return (char*)s1;
}
return NULL;
}
注意:
1.注意判断s2为空的情况
2.使用strncmp来做判断
当s1==s2时,返回值=0
当s1>s2时,返回值 =1
注:c++ 中
当s1<s2时,返回值小于0
当s1==s2时,返回值等于0
当s1>s2时,返回值 大于0
即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止。
6.memcpy
说明
1.source和destin所指的内存区域可以重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前被覆盖。而使用memmove可以用来处理重叠区域。函数返回指向destin的指针。
2.strcpy和memcpy主要有以下3方面的区别。
2.1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2.2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
2.3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
3.如果目标数组destin本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到你要追加数据的地址。
Linux中实现:
void* memcpy(void *dest, const void *src, size_t count)
{
assert(dest!= NULL && src != NULL);
char *tmp = dest;//不能少,转换为char型,保证tmp++按照一个字节寻址
const char *s = src;//
while(count--) //strcpy while( (*dest=*src)!='\0') 遇到\0结束复制
*tmp++ = *s++ ;
return dest;
}
注意:
1.判断结束条件为while(count--)即复制count个字节
2.参数都为void *类型,
3.在进行复制之前,为了保证按一个字节寻址,把void进行类型转换为char型
7.memmove
当源内存和目标内存存在重叠时,memcpy会出现错误,而memmove能正确地实施拷贝,但这也增加了一点点开销。
memmove的处理措施:
(1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
(2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
(3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝
void * memmove(void* dest,void* src,size_t count)
{
char *d =dst;
const char *s =(const char*)src;
if(d<s) //和memcoy一样,正向拷贝
{
while(count--)
*d++=*s++;
}
if(d>s)//反向拷贝
{
d=d+count-1;
s=s+count-1;
while(count--)
*d--=*s--;
}
return dest;
}
8.memset
原型: void *memset(void *buffer, int c, int count);
用法:#include <string.h>
功能:把buffer所指内存区域的前count个字节设置成字符c。
说明:返回指向buffer的指针。
源码实现:
void *memset(void *src, int c, size_t count)
{
assert(src!=NULL);
char *tmpsrc=(char*)src;
while(count--)
*tmpsrc++ =(char)c;
return src;
}
注意:
1.和前面一样,assert判断src是否为空
2.类型转换void转char
编写一个函数,把一个char组成的字符串循环右移n位
思路1:
void loopmove(char temp[],int n)
{
int len=strlen(temp);
char c;
for(int i=0;i<len;i++)
{
c=temp[len-1];//取出最后一位
for(int j=len-2;j>=0;j--)
{
temp[j+1]=temp[j];//剩余len-1位全部右移
}
temp[0]=c;
}
}
思路2:
void loopmove(char*pstr,int steps) { char temp[max]; int n=strlen(pstr)-steps; strcpy(temp,pstr+n); strcpy(temp+steps,pstr); *(temp+strlen(pstr))='\0';//别忘了加\0 strcpy(pstr,temp); }