常考字符串处理函数一网打尽
常考字符串处理函数一网打尽
[题记]:近期笔试、面试中多次出现字符串处理函数的写法。包括最经典的: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;}
【总结】:字符串处理为什么常考的原因,主要它牵涉到指针处理、分支情况的处理,考量大家的思考能力、逻辑问题分析能力、变通能力等。
肯定还有这种常考的函数,希望与大家探讨!