關於c++string類


特別鳴謝由張老師整理(原出處未知

一、C++ 字符串

C++ 提供了以下兩種類型的字符串表示形式:

C 風格字符串

C++ 引入的 string 類類型

1、C 風格字符串

C 風格的字符串起源於 C 語言,並在 C++ 中繼續得到支持。字符串實際上是使用 null 字符 '\0' 終止的一維字符數組。因此,一個以 null 結尾的字符串,包含了組成字符串的字符。

下面的聲明和初始化創建了一個 "Hello" 字符串。由於在數組的末尾存儲了空字符,所以字符數組的大小比單詞 "Hello" 的字符數多一個。

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

依據數組初始化規則,您可以把上面的語句寫成以下語句:

char greeting[] = "Hello";

以下是 C/C++ 中定義的字符串的內存表示:

![C/C++ 中的字符串表示](file:///C:/Users/user/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg)

其實,您不需要把 null 字符放在字符串常量的末尾。C++ 編譯器會在初始化數組時,自動把 '\0' 放在字符串的末尾。

C++ 中有大量的函數用來操作 null 結尾的字符串:

strcpy(s1, s2); 復制字符串 s2 到字符串 s1。

strcat(s1, s2); 連接字符串 s2 到字符串 s1 的末尾。

strlen(s1); 返回字符串 s1 的長度。

strcmp(s1, s2); 如果 s1 和 s2 是相同的,則返回 0;如果 s1<s2 則返回值小於 0;如果 s1>s2 則返回值大於 0。

strchr(s1, ch); 返回一個指針,指向字符串 s1 中字符 ch 的第一次出現的位置。

strstr(s1, s2); 返回一個指針,指向字符串 s1 中字符串 s2 的第一次出現的位置。

2.string類型變量的聲明與初始化

首先,為了在程序中使用string類型,必須包含頭文件 。如下:

#include

注意這里不是string.h,string.h是C字符串頭文件。

string類是一個模板類,位於名字空間std中,通常為方便使用還需要增加:

using namespace std;

聲明一個字符串變量很簡單:

string str;

示例代碼:(下面的代碼演示了string類型變量的聲明與初始化操作的方法,注意與char類型的字符串比較)

#include <iostream>
#include <string>
using namespace std;
int main ( )
{
 string str;  //定義了一個空字符串str
 str = "Hello world";// 給str賦值為"Hello world"
 char cstr[] = "abcde";  //定義了一個C字符串
 string s1(str); //調用復制構造函數生成s1,s1為str的復制品
 cout<<s1<<endl;
 string s2(str,6); //將str內,開始於位置6的部分當作s2的初值
 cout<<s2<<endl;
 string s3(str,6,3);//將str內,開始於6且長度頂多為3的部分作為s3的初值
 cout<<s3<<endl;
 string s4(cstr);//將C字符串作為s4的初值
 cout<<s4<<endl;
 string s5(cstr,3);  //將C字符串前3個字符作為字符串s5的初值。
 cout<<s5<<endl;
 string s6(5,'A');  //生成一個字符串,包含5個'A'字符
 cout<<s6<<endl;
 string s7(str.begin(),str.begin()+5); 
//區間str.begin()和str.begin()+5內的字符作為初值
 cout<<s7<<endl;
 return 0;
}

結果:

Hello world

world

wor

abcde

abc

AAAAA

Hello

二、string的比較等操作

你可以用 ==、>、<、>=、<=、和!=比較字符串,可以用+或者+=操作符連接兩個字符串,並且可以用[]獲取特定的字符。

#include <iostream>
#include <string>
using namespace std;
int main()
{
 string str;
 cout << "Please input your name:"<<endl;
 cin >> str;
 if( str == "Li" )// 字符串相等比較
cout << "you are Li!"<<endl;
 else if( str != "Wang" )  // 字符串不等比較
cout << "you are not Wang!"<<endl;
 else if( str < "Li") // 字符串小於比較,>、>=、<=類似
cout << "your name should be ahead of Li"<<endl;
 else
cout << "your name should be after of Li"<<endl;
 str += ", Welcome!";  // 字符串+=
 cout << str<<endl;
 for(int i = 0 ; i < str.size(); i ++)
cout<<str[i];  // 類似數組,通過[]獲取特定的字符
 return 0;
}

結果:

Please input your name:

Zhang↙

you are not Wang!

Zhang, Welcome!

Zhang, Welcome!

上例中,“ cout<< str[i]; ”可換為: cout<< str.at(i);

三、string特性描述

可用下列函數來獲得string的一些特性:

int capacity()const; //返回當前容量(即string中不必增加內存即可存放的元素個數)

int max_size()const; //返回string對象中可存放的最大字符串的長度

int size()const; //返回當前字符串的字節數,與length()沒有區別,是作為STL容器的屬性而存在,便於符合STL的接口規則。

int length()const; //返回當前字符串的字節數,與size()的功能沒有區別

bool empty()const; //當前字符串是否為空

void resize(int len,char c); //把字符串當前大小置為len,多去少補,多出的字符c填充不足的部分

測試代碼:

#include <iostream>
#include <string>
using namespace std;
int main()
{
 string str;
  if (str.empty())
  cout<<"str is NULL."<<endl;
  else
  cout<<"str is not NULL."<<endl;
 str = str + "abcdefg";
 cout<<"str is "<<str<<endl;
  cout<<"str's size is "<<str.size()<<endl;
    cout<<"str's capacity is "<<str.capacity()<<endl;
 cout<<"str's max size is "<<str.max_size()<<endl;
 cout<<"str's length is "<<str.length()<<endl;
 str.resize(20,'c');
 cout<<"str is "<<str<<endl;
 str.resize(5);
 cout<<"str is "<<str<<endl;
 return 0;
}

程序執行結果為:

str is NULL.

str is abcdefg

str's size is 7

str's capacity is 15

str's max size is 4294967294

str's length is 7

str is abcdefgccc

str is abcde

四、string的查找

由於查找是使用最為頻繁的功能之一,string提供了非常豐富的查找函數:(注:string::npos)

size_type find( const basic_string &str, size_type index );

//返回str在字符串中第一次出現的位置(從index開始查找),如果沒找到則返回string::npos

size_type find( const char *str, size_type index ); // 同上

size_type find( const char *str, size_type index, size_type length );

//返回str在字符串中第一次出現的位置(從index開始查找,長度為length),如果沒找到就返回string::npos

size_type find( char ch, size_type index );

// 返回字符ch在字符串中第一次出現的位置(從index開始查找),如果沒找到就返回string::npos

注意:查找字符串a是否包含子串b,不是用 strA.find(strB) > 0 而是 strA.find(strB) != string::npos 這是為什么呢?(初學者比較容易犯的一個錯誤)

  先看下面的代碼

int idx = str.find("abc");

if (idx == string::npos);

  上述代碼中,idx的類型被定義為int,這是錯誤的,即使定義為 unsigned int 也是錯的,它必須定義為 string::size_type。npos 是這樣定義的: static const size_type npos = -1; 因為 string::size_type (由字符串配置器 allocator 定義) 描述的是 size,故需為無符號整數型別。因為缺省配置器以型別 size_t 作為 size_type,於是 -1 被轉換為無符號整數型別,npos 也就成了該型別的最大無符號值。不過實際數值還是取決於型別 size_type 的實際定義。不幸的是這些最大值都不相同。事實上,(unsigned long)-1 和 (unsigned short)-1 不同(前提是兩者型別大小不同)。因此,比較式 idx == string::npos 中,如果 idx 的值為-1,由於 idx 和字符串string::npos 型別不同,比較結果可能得到 false。因此要想判斷 find()等查找函數的結果是否為npos,最好的辦法是直接比較。

測試代碼:

#include<iostream>
#include<string>
using namespace std;
int main(){
 int loc;
 string s="study hard and make progress everyday! every day!!";
 loc=s.rfind("make",10);
 cout<<"the word make is at index"<<loc<<endl;//-1表示沒找到
 loc=s.rfind("make");//缺省狀態下,從最后一個往前找
 cout<<"the word make is at index"<<loc<<endl;
 loc=s.find_first_of("day");
 cout<<"the word day(first) is at index "<<loc<<endl;
 loc=s.find_first_not_of("study");
 cout<<"the first word not of study is at index"<<loc<<endl;
 loc=s.find_last_of("day");
 cout<<"the last word of day is at index"<<loc<<endl;
 loc=s.find("day");//缺陷狀態下從第一個往后找
 cout<<loc;
 return 0;
}

運行結果:

meiyou

五、其他常用函數

string &insert(int p,const string &s); //在p位置插入字符串s

string &replace(int p, int n,const char *s); //刪除從p開始的n個字符,然后在p處插入串s

string &erase(int p, int n); //刪除p開始的n個字符,返回修改后的字符串

string substr(int pos = 0,int n = npos) const; //返回pos開始的n個字符組成的字符串

void swap(string &s2); //交換當前字符串與s2的值

string &append(const char *s);//把字符串s連接到當前字符串結尾

void push_back(char c)//當前字符串尾部加一個字符c

const char data()const;//返回一個非null終止的c字符數組,data():與c_str()類似,用於string轉const char其中它返回的數組是不以空字符終止,

例:string s1="1234567890"; char const * ss =s1.data(); //ss中的值為s1的字符串

const char c_str()const; //返回一個以null終止的c字符串,即c_str()函數返回一個指向正規C字符串的指針, 內容與本string串相同,用於string轉const char

測試代碼:

#include <iostream>
#include <string>
using namespace std;
int main()
{
 string str1 = "abc123defg";
 string str2 = "swap!";
 cout<<str1<<endl;
 cout<<str1.erase(3,3)<<endl;  //從索引3開始的3個字符,即刪除掉了"123"
 cout<<str1.insert(0,"123")<<endl; //在頭部插入
 cout<<str1.append("123")<<endl;//append()方法可以添加字符串
 str1.push_back('A');  //push_back()方法只能添加一個字符
 cout<<str1<<endl;
 cout<<str1.replace(0,3,"hello")<<endl;
 //即將索引0開始的3個字符替換成"hello"
 cout<<str1.substr(5,7)<<endl; //從索引5開始7個字節
 str1.swap(str2);
 cout<<str1<<endl;
 const char* p = str.c_str();
 printf("%s\n",p);
 return 0;
}

程序執行結果為:

abc123defg

abcdefg

123abcdefg

123abcdefg123

123abcdefg123A

helloabcdefg123A

abcdefg

swap!

swap!

六、與字符串相關的其它函數

1.轉換字符串為整數stoi,stol,stoll

例如:  std::string str1 = "45";   int myint1 = std::stoi(str1);

2. std::atoi, std::atol, std::atoll

與上述轉換string為整數類似的函數還有std::atoi, std::atol, std::atoll 成功時為對應 str 內容的整數值。

    const char *str1 = "3.14159";

​ int num1 = std::atoi(str1);

std::cout << "std::atoi("" << str1 << "") is " << num1 << '\n';

輸出:

std::atoi("3.14159") is 3

3. std::to_string

std::string to_string( int value );

std::string to_string( float value );

返回值:一個包含轉換后值的字符串

4.std::ctype::tolower, std::ctype::toupper

兩個C風格的字符大小寫轉換函數 std::ctype::tolower, std::ctype::toupper 注意:這兩個函數不能用於string類的字符串,只能轉換 char類型的字符。

void try_lower(const std::ctype<wchar_t>& f, wchar_t c)

{

​ wchar_t up = f.tolower(c);

​ if (up != c) {

std::wcout << "Lower case form of '" << c << "' is " << up << '\n';

​ } else {

std::wcout << ''' << c << "' has no lower case form\n";

​ }

}

5. c++ transform用法 大小寫轉換

#include

#include

using namespace std;

char op(char ch)

{ if(ch>='A'&&ch<='Z') return ch+32;

​ else return ch;

}

int main()

{

​ string first,second;

​ cin>>first;

​ second.resize(first.size());

​ transform(first.begin(),first.end(),second.begin(),op);

​ cout<<second<<endl;

​ return 0;

}

6. std::reverse STL函數

可用於反轉string以及一些STL容器中的元素。

void reverse( BidirIt first, BidirIt last );

反轉 [first, last) 范圍中的元素順序

std::vector v{1,2,3};

std::reverse(std::begin(v), std::end(v));

7. 有兩個”XXprintf”函數

sprintf和snprintf,從給定位置加載數據,轉換為字符串等價版本,並將結果寫入各種池。

sprintf指的是字符串格式化命令,主要功能是把格式化的數據寫入某個字符串中。sprintf 是個變參函數。

注意:使用sprintf 對於寫入buffer的字符數是沒有限制的,這就存在了buffer溢出的可能性。解決這個問題,可以考慮使用 snprintf函數,該函數可對寫入字符數做出限制。類似問題的函數還有strcpy()、strcat(),其對應的安全版為:strncpy() 、strncat()。

1int sprintf( char* buffer, const char* format, ... );

寫結果到字符串 buffer 。

2int snprintf( char* buffer, std::size_t buf_size, const char* format, ... );

寫結果到字符串 buffer 。至多寫 buf_size - 1 個字符。產生的字符串會以空字符終止,除非 buf_size 為零。若 buf_size 為零,則不寫入任何內容,且 buffer 可以是空指針,然而依舊計算返回值(會寫入的字符數,不包含空終止符)並返回。

參數說明:

buffer - 指向要寫入的字符串的指針

format - 指向指定如何轉譯數據的空終止多字節字符串的指針。

格式字符串由普通多字節字符(除了 % )和轉換指定構成,前者被復制到輸出流而無更改。每個轉換指定擁有下列格式:

示例代碼:
double num=3.1415926;
	cout <<"double num="<< num <<endl;   //輸出:
	char *s ;
	sprintf( s,"%.4lf",num);
	cout << "sprintf( s,\"%.4lf\",num)  -> s=" <<s<<endl;
	return 0;                        
運行結果:
double num=3.14159
sprintf( s,"%.4lf",num)  -> s=3.1416

示例代碼:
char a[16];
  size_t i;
  i = snprintf(a, 13, "%012d", 12345);  // 第 1 種情況
  printf("i = %lu, a = %s\n", i, a);    // 輸出:i = 12, a = 000000012345
  i = snprintf(a, 9, "%012d", 12345);   // 第 2 種情況
  printf("i = %lu, a = %s\n", i, a);    // 輸出:i = 12, a = 00000001       

函數的用法與區別

1、cin>>

用法1:最基本,也是最常用的用法,輸入一個數字:

#include

using namespace std;

main ()

{

int a,b;

cin>>a>>b;

cout<<a+b<<endl;

}

輸入:2[回車]3[回車] 輸出:5

用法2:接受一個字符串,遇“空格”、“TAB”、“回車”都結束

#include

using namespace std;

main ()

{

char a[20];

cin>>a;

cout<<a<<endl;

}

輸入:jkljkljkl 輸出:jkljkljkl

輸入:jkljkl jkljkl //遇空格結束,所以不能輸入多個單詞 輸出:jkljkl

2、cin.get()

用法1: cin.get(字符變量名)可以用來接收字符

#include

using namespace std;

main ()

{

char ch;

ch=cin.get(); //或者cin.get(ch);只能獲取一個字符

cout<<ch<<endl;

}

輸入:jljkljkl 輸出:j

用法2:cin.get(字符數組名,接收字符數目)

用來接收一行字符串,可以接收空格

#include

using namespace std;

main ()

{

char a[20];

cin.get(a,20); //有些類似getline。可以輸入多個單詞,中間空格隔開。

cout<<a<<endl;

}

輸入:jkl jkl jkl 輸出:jkl jkl jkl

輸入:abcdeabcdeabcdeabcdeabcde (輸入25個字符)

輸出:abcdeabcdeabcdeabcd (接收19個字符+1個'\0')

用法3:cin.get(無參數)

沒有參數主要是用於舍棄輸入流中的不需要的字符,或者舍棄回車,彌補cin.get(字符數組名,接收字符數目)的不足.

3、cin.getline() //接受一個字符串,可以接收空格並輸出

#include

using namespace std;

main ()

{

char m[20];

cin.getline(m,5); //與上面基本相同。

cout<<m<<endl;

}

輸入:jkljkljkl 輸出:jklj

接受5個字符到m中,其中最后一個為'\0',所以只看到4個字符輸出;

如果把5改成20:

輸入:jkljkljkl 輸出:jkljkljkl

輸入:jklf fjlsjf fjsdklf 輸出:jklf fjlsjf fjsdklf

//延伸:

//cin.getline()實際上有三個參數,cin.getline(接受字符串到m,接受個數5,結束字符)

//當第三個參數省略時,系統默認為'\0' 是‘/n’吧。

//如果將例子中cin.getline()改為cin.getline(m,5,'a');當輸入jlkjkljkl時輸出jklj,輸入jkaljkljkl時,輸出jk

當用在多維數組中的時候,也可以用cin.getline(m[i],20)之類的用法:

#include

#include

using namespace std;

main ()

{

char m[3][20];

for(int i=0;i<3;i++)

{

cout<<"\n請輸入第"<<i+1<<"個字符串:"<<endl;

cin.getline(m[i],20);

}

cout<<endl;

for(int j=0;j<3;j++)

cout<<"輸出m["<<j<<"]的值:"<<m[j]<<endl;

}

請輸入第1個字符串:kskr1

請輸入第2個字符串:kskr2

請輸入第3個字符串:kskr3

輸出m[0]的值:kskr1

輸出m[1]的值:kskr2

輸出m[2]的值:kskr3

4、getline() // 接受一個字符串,可以接收空格並輸出,需包含“#include

#include

#include

using namespace std;

main ()

{

string str;

getline(cin,str);

cout<<str<<endl;

}

輸入:jkljkljkl //VC6中有個bug,需要輸入兩次回車。 輸出:jkljkljkl

輸入:jkl jfksldfj jklsjfl 輸出:jkl jfksldfj jklsjfl

和cin.getline()類似,但是cin.getline()屬於istream流,而getline()屬於string流,是不一樣的兩個函數

5、gets() // 接受一個字符串,可以接收空格並輸出,需包含“#include

#include

#include

using namespace std;

main ()

{

char m[20];

gets(m); //不能寫成m=gets();

cout<<m<<endl;

}

輸入:jkljkljkl 輸出:jkljkljkl

輸入:jkl jkl jkl 輸出:jkl jkl jkl

類似cin.getline()里面的一個例子,gets()同樣可以用在多維數組里面:

#include

#include

using namespace std;

main ()

{

char m[3][20];

for(int i=0;i<3;i++)

{

cout<<"\n請輸入第"<<i+1<<"個字符串:"<<endl;

gets(m[i]);

}

cout<<endl;

for(int j=0;j<3;j++)

cout<<"輸出m["<<j<<"]的值:"<<m[j]<<endl;

}

請輸入第1個字符串:kskr1

請輸入第2個字符串:kskr2

請輸入第3個字符串:kskr3

輸出m[0]的值:kskr1

輸出m[1]的值:kskr2

輸出m[2]的值:kskr3

自我感覺gets()和cin.getline()的用法很類似,只不過cin.getline()多一個參數罷了;

這里順帶說明一下,對於本文中的這個kskr1,kskr2,kskr3的例子,對於cin>>也可以適用,原因是這里輸入的沒有空格,如果輸入了空格,比如“ks kr jkl[回車]”那么cin就會已經接收到3個字符串,“ks,kr,jkl”;再如“kskr 1[回車]kskr 2[回車]”,那么則接收“kskr,1,kskr”;這不是我們所要的結果!而cin.getline()和gets()因為可以接收空格,所以不會產生這個錯誤;

6、getchar() //接受一個字符,需包含“#include

#include

using namespace std;

main ()

{

char ch;

ch=getchar(); //不能寫成getchar(ch);

cout<<ch<<endl;

}

輸入:jkljkljkl 輸出:j

//getchar()是C語言的函數,C++也可以兼容,但是盡量不用或少用;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM