你不得不熟悉的字符串處理函數

常見字符串處理函數的實現



1、C語言庫函數中有兩個函數實現數字和字符串之間的相互轉換:將數字轉換成字符串的函數itoa();將字符串轉換爲數字的函數atoi(),下面是這兩個函數的內部實現:


#include<stdlib.h>
#include<stdio.h>
#include <iostream>
using namespace std;

//字符串轉換爲數字
int My_atoi(char str[]){
	int n, i = 0, sign = 1;
	while(isspace(str[i]))i++;	//跳過前面的空白字符
	if(str[i] == '-') {
		sign = -1;		//記住符號位
		i++;			//跳過符號位
	}
	for(n = 0; str[i] != '\0'; i++){
		n = 10*n + (str[i] - '0');	//取str的最高位
	}
	return n*sign;
}

//整型數字轉換爲字符串
void My_itoa(int n, char str[]){
	char *tmp = str;			//保留基址
	bool sign = (n<0 ? true : false);	//是否爲負數
	n = (n>=0 ? n : -n);		//取絕對值
	do{
		*str++ = n%10 + '0';	//取n的最低位
	}
	while(n /= 10);
	if(sign) *str++ = '-';		//添加符號位
	*str = '\0';				//加空字符結尾
	//反轉字符串
	for(--str; tmp<str; ++tmp,--str){
		*tmp ^= *str;
		*str ^= *tmp;
		*tmp ^= *str;
	}
}

int main(){
	char str[10] ;
	My_itoa(-1020, str);
	cout<<"itoa(-1020) = \""<<str<<"\""<<endl;
	cout<<"atoi(\"-1020\") = "<<My_atoi(str);
	return 0;
}

結果:

itoa(-1020) = "-1020"
atoi("-1020") = -1020

2、字符串拷貝函數strcpy()和更加通用的內存拷貝函數memcpy():strcpy()函數在各種面試筆試中被嚴重濫用了,就不多廢話了,直接給出代碼先。順便提下,如果有人問你該函數爲啥要返回char*類型,標準答案就是爲了支持鏈式表達式 :-)

//字符串拷貝函數
char* My_strcpy(char *strDest, const char *strSrc){
	assert((strDest!=NULL) && (strSrc!=NULL));//確認源字符串和目標字符串不爲空
	char *tmp = strDest;	//保留基址
	while((*strDest++ = *strSrc++) != '\0');
	*strDest = '\0';
	return tmp;
}

int main(){
	char s[] = "123456789";
	char d[] = "123";
	My_strcpy(d, s);
	cout<<s<<endl;
	cout<<d<<endl;

	return 0;
}

結果:

56789
123456789

這個結果相當詭異吧,源字符串居然被改寫了!這是因爲程序中並沒有爲目標字符串分配足夠的存儲空間,使他霸佔了相鄰的源字符串的內存空間。如果把源字符串和目標字符串的定義順序反過來,就可以得到正確的輸出了:

int main(){
	char d[] = "123";
	char s[] = "123456789";
	My_strcpy(d, s);
	cout<<s<<endl;
	cout<<d<<endl;

	return 0;
}
結果:
123456789
123456789

strcpy()函數雖然很簡單,但在使用前一定能要確保目標字符串有足夠的存儲空間容納整個源字符串,函數本身並不會做這種檢查,只能靠程序員自己來保證。
strcpy()函數只能拷貝字符串,遇到空字符結束。如果要拷貝其他類型的數據,需要使用到memcpy()函數,使用該函數要指定拷貝的字節數。該函數的實現代碼如下:

//內存拷貝函數
void* My_memcpy(char *pvTo, char *pvFrom, int n){
	assert((pvTo!=NULL) && (pvFrom!=NULL));	//使用斷言
	char *address = pvTo;	//保留基址
	while(n--)*pvTo++ = *pvFrom++;
	return address;
}

3、編寫string類的構造函數、析構函數和賦值函數。


//string類的聲明
class String{
public:
	String(const char *str = NULL);
	~String(void);
	String& operator =(const String &other);
private:
	char *m_data;
};

//string類的實現
//析構函數
String::~String(void){
	delete []m_data;	//釋放內存
}

//構造函數
String::String(const char *str){
	if(str == NULL){
		m_data = new char[1];	//默認構造函數,返回一個空字符串
		*m_data = '\0';
	}
        else {
	        m_data = new char[strlen(str)+1];
	        strcpy(m_data, str);
             }
}

//複製構造函數
String::String(const char &other){
	m_data = new cahr[strlen(other.m_data)+1];
	strcpy(m_data,other.m_data);
}

//賦值函數
String& String::operator =(const String &other){
	if(this == &other){	//檢查自賦值
		return *this;
	}
	delete [] m_data;
	m_data = new char [strlen(other.m_data)+1];
	strcpy(m_data, other.m_data);
	return *this;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章