1,strlen
①计数法
unsigned int my_strlen1(const char *str)
{
unsigned int count=0;
assert(str);
while(*str){
count++;
str++;
}
return count;
}
②递归法
unsigned int my_strlen2(const char *str)
{
if(*str=='\0')
return 0;
return my_strlen2(str+1)+1;
}
③首尾相减法
unsigned int my_strlen3(const char *str)
{
assert(str);
const char *end=str;
while(*end++);
return end-str-1;
}
2,strcpy
dest字符串要有足够的空间,src复制包括'\0'在内的字符串到dest中。
char *my_strcpy(char *dest,const char *src)
{
char *tmp=dest;
assert(dest&&src);
while(*dest++=*src++);
return tmp;
}
3,strncpy
src复制len个字符串到dest中,len如果比src长,则继续复制'\0'。len比src小时,复制len个,最后并添加'\0'。原strncpy最后没有添加'\0'。
char *my_strncpy(char *dest,const char *src,unsigned int len)
{
assert(dest&&src);
char *tmp=dest;
while(len--){
if((*dest++=*src)!='\0')
src++;
}
*dest='\0';/*确保dest后有'\0',strncpy 没有这步,但是如果dest位置全部用完也没办法*/
return tmp;
}
4,strcat
先遍历dest到'\0'位置,然后进行复制
char *my_strcat(char *dest,const char *src)
{
char *tmp=dest;
assert(dest&&src);
while(*dest!='\0')
dest++;
while(*dest++=*src++);
return tmp;
}
5,strncat
len就算比src的长度长 也不会像stcncpy继续添加'\0',而是src遇到'\0' 就结束
char *my_strncat(char *dest,const char *src,unsigned int len)
{
assert(dest&&src);
char *tmp=dest;
while(*dest)
dest++;
while(len--&&(*dest++=*src++));
*dest='\0';/*目标串始终以'\0'结束,strncat也是这么实现的*/
return tmp;
}
6,strcmp
int my_strcmp(const char *str1,const char *str2)
{
assert(str1&&str2);
/*第二个条件的作用,如果没有第二个条件当两个都为""只有一个\0字符时 就会奔溃*/
while(*str1==*str2&&*str2){
str1++;
str2++;
}
return *str1-*str2;
}
7,strncmp
int my_strncmp(const char *str1,const char *str2,unsigned int len)
{
assert(str1&&str2);
while(len--&&*str2){
if(*str1!=*str2){
return *str1-*str2;
}
str1++;
str2++;
}
return 0;
}
8,strchr
在一个字符串中查找一个字符第一次出现的位置,如果没有则返回NULL
char *my_strchr(const char *str,char ch)
{
assert(str);
const char *tmp=str;
while(*tmp){
if(*tmp==ch)
return tmp;
tmp++;
}
return NULL;
}
9,strrchr
查找一个字符在字符串最后出现的位置,没有则返回NULL
char *my_strrchr(const char *str,char ch)
{
assert(str);
const char *tmp=str;
const char *ptr=NULL;
while(*tmp){
if(*tmp==ch){
ptr=tmp;
}
tmp++;
}
return ptr;
}
10,strstr
在str1找第一次出现str2的起始位置,如果没有则返回NULL,str2为空字符串则返回str1
char *my_strstr(const char *str1,const char *str2)
{
assert(str1&&str2);
const char *cur=str1;
const char *tmp=str2;
if(*str2=='\0'){
return str1;
}
while(*str1){
while((*str1)&&(*str2)&&(*str1==*str2)){
str1++;
str2++;
}
if(*str2=='\0'){
return cur;
}
cur++;
str1=cur;
str2=tmp;
}
return NULL;
}
11,atoi
字符串转换为int型整数,字符串前面允许有若干空格,和+,-号。符号位后面必须是数字字符才算有效,如果遇到非法字符,则停止转换,返回前面转换好的数字。
需要考虑的问题:
- 指针是否为NULL
- 字符串是否为空串:空串为0
- 空白字符
- 正负号问题
- 溢出问题
- 异常字符处理
一些情况
" 1234" ->1234
" +1234" ->1234
" -1234" ->-1234
"-123 4" ->-123
"a1234" ->0
"+ 1234" ->0
"" ->0
int my_atoi(const char *str)
{
assert(str);
int ret=0;
int flag=1;
const char *tmp=str;
while(isspace(*tmp)){
tmp++;
}
if(*tmp=='-'){
flag=-1;
tmp++;
}
else if(*tmp=='+'){
tmp++;
}
while(*tmp){
if(isdigit(*tmp)){
ret=ret*10+*tmp-'0';
if(ret>INT_MAX||ret<INT_MIN){
return flag*ret;
}
}
else{
break;/*异常字符*/
}
tmp++;
}
return flag*ret;
}
12,itoa
linux没有这个函数,windows上有,且有进制选择,下面只实现10进制的情况
char *my_itoa(int num,char *buf)
{
assert(buf);
int tmp=0;
int i=0,j=0;
int flag=0;
if(num==0){
buf[0]='0';
buf[1]='\0';
return buf;
}
if(num<0){
num=-num;
flag=1;
}
buf[i++]='\0';//开始把第一个字符设为'\0'
while(num){
tmp=num%10;
buf[i++]=tmp+'0';
num/=10;
}
if(flag==1){
buf[i]='-';
}
else{
i--;
}//把倒序的字符串翻转
while(j<i){
tmp=buf[j];
buf[j]=buf[i];
buf[i]=tmp;
j++;
i--;
}
return buf;
}
13,memset
void* my_memset(void *src,int ch,int n)
{
assert(src);
void* ret=src;
char *p=(char*)src;
int i=0;
while(n--)
{
*p++=ch;
}
return ret;
}
14,memcpy(不能正确处理有重复,且src在dest前的情况)
void* my_memcpy(void *dest,void *src,int n)
{
assert(dest);
assert(src);
void* ret=dest;
char* str1=(char*)dest;
char* str2=(char*)src;
while(n--)
{
*str1++=*str2++;
}
return ret;
}
15,memmove(利用处理上述情况)
void* my_memmove(void* dest,void* src,int n)
{
assert(dest);
assert(src);
void* ret=dest;
char* str1=(char*)dest;
char* str2=(char*)src;
if(src>dest)
{
while(n--)
{
*(str1+n)=*(str2+n);
}
}
else
{
while(n--)
{
*str1++=*str2++;
}
}
return ret;
}