常考字符串处理函数一网打尽

常考字符串处理函数一网打尽

[题记]:近期笔试、面试中多次出现字符串处理函数的写法。包括最经典的:strcpy、strcat、strcmp、atoi、itoa,内存拷贝函数memcpy等。

Baidu、google一下会有很多版本,良莠不齐,给大家阅读和辨识形成了负担,本就紧张的笔试、面试备战在选择中浪费了不少时间。

本文涉及的函数的写法不敢说最优,但是是作者参考了诸多文献和深入分析下总结的,并全部通过VC6.0调试通过,希望对大家有帮助。

 

这里涉及一点,面试的时候,面试官可能就一张白纸,不提供函数原型的情况下让你实现库函数。这里就需要大家对Msdn里提供的库函数有所深入,参数个数、参数类型、返回值类型、函数实现的功能。

一、函数原型

以下函数原型摘自MSDN2001,VS2008、VS2010会有新的扩展比如:strcpy_s——

函数原型

函数功能

char *strcpy( char *strDestination,const char *strSource);

字符串拷贝(拷贝一个字符串到另一个字符串)

int strcmp( const char *string1, const char *string2 );

比较两字符串,string1>string 返回值>0;string1<string2 返回值<0; string1==string2返回0.

char *strcat( char *strDestination, const char *strSource );

字符串拼接函数

int atoi( const char *string );

字符串转化为整形数

char *_itoa( int value, char *string, intradix );

整形转化为字符串[注意]:radix取值范围是[2,36].string长度最长33个字节.10进制的数考虑负数的处理,其他进制不必考虑。

void *memcpy( void *dest, const void *src, size_tcount );

内存拷贝函数,【注意】:本身并没涉及地址覆盖,但一般面试的时候需要考虑。

 

二、自写函数实现

1. strcpy的实现

char* strcpy_t(char* strDst, const char* strSrc)
{
assert(strDst !=NULL && strSrc != NULL);
 
char* strRst =strDst;
while( (*strDst++= *strSrc++)!='\0');
return strRst;
}

 

2. strcmp的实现[扩展:<0 返回-1; >0 返回1; 等于0 返回0]

int strCmp_t(const char* strSrcL, const char* strSrcR)
{
         assert(strSrcL!= NULL || strSrcR != NULL);
        
         int ret = 0;
         constchar* p1 = strSrcL;
         constchar* p2 = strSrcR;
        
         while(!(ret = (*p1 - *p2)) && *p2 != '\0') //注意循环终止条件
         {
              ++p1;
              ++p2;
         }
         if(ret< 0)
         {
              ret= -1;
         }
         else if(ret > 0)
         {
              ret= 1;
         }
         return ret;
}


3. strcat的实现

char* strCat_t(char* strDst, const char* strSrc)
{
         char* cp = strDst;
        
         while(*cp != '\0')
         {
                   cp++;//跳至 strDst的末尾.
         }
        
         while((*cp++= *strSrc++)!='\0');
         return strDst;
}

4.atoi的实现【扩展:考虑了正负号的处理、大、小边界数的处理、非字符的处理、status决定了是什么状态导致的返回0】

//atoi_t

enum status{kValid = 0, kInvalid};
int g_Status =kInvalid;
 
int main()
{
            int stringToInt(const char* str);
            int stringToIntCore(const char* str,bool bMinus);
           
            char* str1 = "-12345";
            cout << stringToInt(str1)<< endl;
            cout <<stringToInt("+") << endl;
           
            return 0;
}
 
//stringToIntCore核心处理函数.
intstringToIntCore(const char* str, bool bMinus)
{
         int num = 0;
        
         while(*str!= '\0')
         {
                   if(*str>= '0' && *str <='9')
                   {
                     num= num*10 + (*str -'0');
                     if((!bMinus && num >0x7FFFFFFF) || (bMinus && num < (signedint)0x80000000))
                     {
                        num= 0;  //
                        break;
                     }
                   }
                   else
                   {
                       num= 0;
                       break;
                   }
                   str++;
         }//endwhile
        
         if(bMinus)
         {
                   num= -num;
         }
        
         if(*str== '\0')
         {
                   g_Status= kValid;
         }
        
         returnnum;
}
 
intstringToInt(const char* str)
{
         boolbMinus = false;
         intnum = 0;
        
         if(str== NULL)
         {
               return0;
         }
         if(str!= NULL && *str != '\0')
         {
                   if(*str== '+')
                   {
                            str++;
                   }
                   else if(*str == '-')
                   {
                            bMinus= true;
                            str++;
                   }
                  
                   if(*str!= '\0')
                   {
                       num = stringToIntCore(str,bMinus);
                   }
                  
         }//endif
        
         return num;
}


5.itoa的实现[考虑,进制转换,字符串翻转]

//itoa

char* itoa_t(intvalue, char* strSrc, int radix)
{
                char strTmp[33];    //1.最大存储33个字节
                int quotient = 0;   //商数
                int residue = 0;    //余数
                int isNegative = 0;  //负数标识,1代表负数,0代表正数
                int nCnt = 0;       //统计字符个数
                char* strQ = strTmp;    //暂存strTmp.
               
                if(radix < 2 || radix >36)
                {
                   return NULL;             //2.radix[2,36]基数的大小范围
                }
               
                isNegative = (value < 0&& radix == 10); //3.对于10进制的数,考虑负数的处理.
                if(isNegative != 0)
                {
                   value = -value;
                }
                else
                {
                   value =(unsigned)value;
                }
               
                while(value != 0)
                {
                   quotient = value/radix; //商
                   residue = value%radix; //余数
                   ++nCnt;
                  
                   if(residue <10)
                   {
                       *strQ++ =(residue+'0');
                   }
                   else
                   {
                       *strQ++ =(residue+'a'-10); //>=10 的特殊处理a-->f
                   }
                   value = quotient;
                }
               
                if(strSrc == NULL)
                {
                   strSrc =(char*)malloc(nCnt+isNegative+1);
                }
               
                char* strP = strSrc;  //strP暂存strSrc变化
                if(isNegative != 0)
                {
                   *strP++ = '-';
                }
                while(nCnt >= 0)
                {
                   *strP++ = *--strQ;
                   --nCnt;
                }
                *strP = '\0';
               
                return strSrc;
}


6. memcpy的实现——见另一篇博文.http://blog.csdn.net/wojiushiwo987/article/details/8020409


7. 字符串翻转.

char* strRvs(const char* strSrc)
{
         intnLen = strlen(strSrc);
         char*strRst = new char[nLen+1];  //另外开辟空间.
         char*pRst = strRst;
         const char* pLast = strSrc + nLen-1;
 
         while(nLen>= 0)
         {
                   *pRst++= *(pLast--);
                   nLen--;
         }
 
         return strRst;
}

8.strncat写法

char *strncat_t (char * front,const char * back,size_t count)    
{    
   char *start = front;    
	   
	while (*front++)    
		    ;    
    front--;    
    
	while (count--) 
	{
	   if (!(*front++ = *back++))
	   {
		   return(start); //拷贝至结尾需要返回!
	   }
	}
	    
	*front = '\0';    
	return(start);    
}    


9.memset写法
//memset():把指定内存区域的前count个字节设置成字符c  
void * memset_t(void* buffer, int c, size_t count)  
{  
   assert(buffer != NULL);  
   char *p = (char *)buffer;  
   cout << p << endl;


    while(count--) 
	{
		*p++ = 'c';
		cout << *p << endl;
	}
    return buffer;  
}  

10.strstr写法

/子串判定!
char *strstr_t(const char *strSrc, const char *str)     
{     
   assert(strSrc != NULL && str != NULL);     
   const char *s = strSrc;     
   const char *t = str;     
   for (; *strSrc != '\0'; ++ strSrc)     
   {     
		for (s = strSrc, t = str; *t != '\0' && *s == *t; ++s, ++t)           
		{
			  NULL;  
		}
		if (*t == '\0')     
		{
			 return (char *) strSrc;  //存在子串
		}
   }     
   return NULL;     
}   


【总结】:字符串处理为什么常考的原因,主要它牵涉到指针处理、分支情况的处理,考量大家的思考能力、逻辑问题分析能力、变通能力等。

肯定还有这种常考的函数,希望与大家探讨!

发布了359 篇原创文章 · 获赞 2735 · 访问量 329万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 代码科技 设计师: Amelia_0503

分享到微信朋友圈

×

扫一扫,手机浏览