C++ 字符串

    科技2023-12-18  103

    C++ 字符串

    C++ 提供了以下两种类型的字符串表示形式:

    C 风格字符串

    C++ 引入的 string 类类型(string class type)

    C语言没有提供字符串类型,使用元素类型为char的数组代替,具体而言,字符串一般用一维字符数组来存放,还可以用二维字符数组可以存放多个字符串。

    C++ 大大增强了对字符串的支持,除了可以使用C风格的字符串,还可以使用内置的 string 类。string 类处理起字符串来会方便很多,完全可以代替C语言中的字符数组或字符串指针。

     

    一、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风格字符串时,您不需要把 null 字符放在字符串常量的末尾。C++ 编译器会在初始化数组时,自动把 '\0' 放在字符串的末尾。

    输出上面的字符串的代码:

    #include <iostream>

    using namespace std;

     int main ()

    {

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

       cout << greeting << endl;

     

       return 0;

    }

    运行之,参见下图:

    C语言没有提供字符串类型,使用元素类型为char的数组代替,具体而言,字符串一般用一维字符数组来存放,还可以用二维字符数组可以存放多个字符串。

    字符数组定义的一般格式为:

    一维字符数组:char 数组名[整型常量表达式];

    二维字符数组:char 数组名[整型常量表达式1][整型常量表达式2];

    如: char cA[10],cB[2][15];

     

    字符数组的初始化与赋值与一般数组的很相似,但也有其特殊之处。

    一维字符数组的初始化

    如下例:

    char cA[5]={ ' a', 'b', 'c', 'd', 'e'};

    这是最基本的初始化方式。在初始化时要注意数组元素存放的是字符,因此用单引号而不是用双引号,如下面的初始化:

    char cA[5]={ " a","b","c","d","e"}; //错误初始化方式

    这时每个元素的初值变成了字符串,这显然是错误的。

     

    当字符数组用来存放字符串时,要注意字符串中包含了一个字符串结束标志'\0',这个结束标志也要占用一个单元。其初始化方式有以下几种:

    ☆用{ }列出初值列表实现。如:

    char s1[5]={ 'a', 'b', 'c', 'd', '\0'};

    s1中存放的是字符串"abcd"

    ☆用字符串常量直接初始化。如:

    char s1[5]= "abcd";

    这种方式初始化时,一定要注意数组的长度和字符串的长度的关系:字符串长度不包含结束符'\0',数组长度要把结束符算在其内,因此数组的长度要大于字符串的长度。如下面的操作是错误的:

    char s1[5]= "abcde"; /*数组的空间不够存放字符串*/

    ☆ 省略数组的大小,进行初始化。这是根据初值中字符的个数确定数组的长度。如:

    char s2[]="hello";

    它等价于 char s2[6]= "hello";

    赋值

    与一般数组赋值相同,不能将一个字符串直接赋值给一个数组名,只能对字符数组的元素逐个赋值。如:

    char sC[6];

    要给它赋值为"hello",只能如下方式:

    sC[0]= 'h',sC[1]= 'e',sC[2]= 'l',sC[3]= 'l',sC[4]= 'o',sC[5]= '\0';

    而不能是:sC="hello";

    也不能是:sC[6]= "hello";

    注意:C/C++语言中,无论是字符数组还是数值型数组在程序中只能给它的元素赋值。

    字符数组的输入输出

    其它类型的数组元素在输入输出时,只能逐个元素实现输入输出,但用字符数组来存放字符串时,可以进行整体的输入输出,当然也可以使用循环将字符数组中的字符一个一个处理输入输出。

    一维字符数组的输入输出

    例、元素类型为char的数组输入输出例

    #include <iostream>

    using namespace std;

    int main ()

    {

       char s[10];

       cout << "请输入字符串:" ;

       cin >>s;  //scanf(" %s",s);

       cout << "字符串是:" << s << endl; // printf("符串是是: %s ",s);

       

       return 0;

    }

     

    运行之,参见下图:

     

    C风格字符串将字符串放在字符数组中,并以空字符'\0'结束,一般利用指针来操作这些字符串。尽管C++支持C风格字符串,但建议在C++程序中尽量不要使用它们。一些用于操作C风格字符串的标准库函数定义在cstring头文件中,是C语言头文件string.h的C++版本。

    1)字符串复制函数:

        char *strcpy(char *s,const char ct)

    返回值是指向复制后字符串中首字符的指针。。

    例子

    #include <iostream>

    //#include <string.h>

    #include <cstring>

    using namespace std;

     

    int main ()

    {

       char str[] = "just test";

       char des[20];

      

       //cout << strcpy(des, str)<< endl;  //本句和下面两句效果相同,但下面两句更直观说明 strcpy()的含义

       strcpy(des, str);

       cout << des<< endl;

     

       return 0;

    }

     

    运行,参见下图:

     

    2)字符串连接函数:char *strcat(char *s,const char *ct)

    将串ct复制到串s的后面,形成一个长串。例如:

    #include <iostream>

    //#include <string.h>

    #include <cstring>

    using namespace std;

     

    int main ()

    {

       char str1[]="李小明";

       char str2[]="是大学生";

      

       //cout << strcat(str1,str2)<< endl;  //本句和下面两句效果相同

       strcat(str1,str2);

       cout <<str1<< endl;

     

       return 0;

    }

     

    运行,参见下图:

     

    3)字符串比较函数:int strcmp(const char *cs,const char ct)。

    两字符串比较是按字典排序方法进行。两个字符串从第一个字符比较起,如果相同,则比较第二个字符,依此类推,直到不同。哪个字符串对应的字符的ASCII码值大,串就大。如果两串直到结束符都相同,则一样大。若两个字符串相等,则返回0;串cs大,则返回正整数;串ct大,则返回负整数。

    #include <iostream>

    //#include <string.h>

    #include <cstring>

    using namespace std;

     

    int main ()

    {

       char strA[] = "Hello world";

       char strB[] = "Hello, world";

     

       cout << strcmp(strA, strB)<< endl;

     

       return 0;

    }

     

    运行,参见下图:

     

    4)求字符串长度函数:int strlen(const char *s)

    这里求出的串长度不包含串结束符在内。而sizeof运算符包括结束符,还包括没有使用的单元。

    #include <iostream>

    //#include <string.h>

    #include <cstring>

    using namespace std;

     

    int main ()

    {

       char str[] = "Hello world";

     

       cout << strlen(str) << endl;

     

       return 0;

    }

     

    运行,参见下图:

     

    现在简要介绍二维字符数组

    二维字符数组的初始化

    与其它二维数组初始化一样,有以下几种方式:

    ☆用初值列表方式。如:

    char s3[2][4]={{ ' a', 'b', 'c', '\0'},{' m', 'n', 'l', '\0'}};

    ☆用字符串常量方式。如:

    char s3[2][4]={ " abc"," mnl"};

    ☆省略第一维大小的方式来初始化。如:

    char s3[][4]={{ ' a', 'b', 'c', '\0'},{' m', 'n', 'l', '\0'}};

    char s3[][4]={ " abc","mnl"};

    根据分行赋值的大括号{}的个数或常量字符串的个数确定第一维的大小为2。

     

    二维字符数组的输入输出

    二维字符数组的每一行可以用来存放一个字符串,因此可以将二维字符数组看成是一个一维数组,数组中的元素为字符串,即被看作是字符串数组。如:

    char ss[3][10];

    数组ss可以被看作是用来存放3个字符串的字符串数组,每个字符串的长度不超过9。这时,对数组中字符串的引用,只使用第一个下标。即:

    ss[0]:表示第一个字符串的首地址;

    ss[1]:表示第二个字符串的首地址;

    ss[2]:表示第三个字符串的首地址;

    元素类型为char的二维数组输入输出例:

    #include <iostream>

    using namespace std;

    int main ()

    {

       char ss[3][10];

       int i;

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

           {

               cout << "请输入字符串:" ;

            cin >>ss[i];  //scanf(" %s",ss[i]);

             } 

          

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

           cout << "字符串" << i + 1 << "是:"<< ss[i] << endl; // printf("字符串%d是:%s ",,i+1,ss[i]);

       

       return 0;

    }

     

    运行,参见下图:

     

     

    二、C++ 中的 String 类

    使用 string 类需要包含头文件<string>

    C++ 标准库提供了 string 类类型(string class type),支持上述所有的操作,另外还增加了其他更多的功能。我们将学习 C++ 标准库中的这个类,现在让我们先来看看下面这个实例:

    现在您可能还无法透彻地理解这个实例,因为到目前为止我们还没有讨论类和对象。所以现在您可以只是粗略地看下这个实例,等理解了面向对象的概念之后再回头来理解这个实例。

    #include <iostream>

    #include <string>

    using namespace std;

     

    int main ()

    {

       string str1 = "Hello";

       string str2 = "World";

       string str3;

       int  len ;

     

       // 复制 str1 到 str3

       str3 = str1;

       cout << "str3 : " << str3 << endl;

     

       // 连接 str1 和 str2

       str3 = str1 + str2;

       cout << "str1 + str2 : " << str3 << endl;

     

       // 连接后,str3 的总长度

       len = str3.size();

       cout << "str3.size() :  " << len << endl;

     

       return 0;

    }

     

    运行之,参见下图:

     

    定义 string 变量(对象)的方法:

    string s1;

    string s2 = "c plus plus";

    string s3 = s2;

    string s4 (5, 's');

    变量 s1 只是定义但没有初始化,编译器会将默认值赋给 s1,默认值是"",也即空字符串。

    变量 s2 在定义的同时被初始化为"c plus plus"。与C风格的字符串不同,string 的结尾没有结束标志'\0'。

    变量 s3 在定义的时候直接用 s2 进行初始化,因此 s3 的内容也是"c plus plus"。string 变量也可以用C风格的字符串进行赋值。

    变量 s4 被初始化为由 5 个's'字符组成的字符串,也就是"sssss"。

     

    当我们需要知道字符串长度时,可以调用 string 类提供的 length() 函数。如

    string s = "http://c.biancheng.net";

    int len = s.length(); //结果为22。string 的末尾没有'\0'字符,所以 length() 返回的是字符串的真实长度,而不是长度 +1。

     

    string 类为我们提供了一个转换函数 c_str(),该函数能够将 string 字符串转换为C风格的字符串,并返回该字符串的 const 指针(const char*)。例如

    string path = "D:\\demo.txt";

    path.c_str()

     

    string 字符串的输入输出

    string 类重载了输入输出运算符,可以像对待普通变量那样对待 string 变量,也就是用>>进行输入,用<<进行输出。例:

    #include <iostream>

    #include <string>

    using namespace std;

    int main(){

        string s;

        cin>>s;  //输入字符串

        cout<<s<<endl;  //输出字符串

        return 0;

    }

     

     

    下面介绍字符串的常见操作。

    ☆访问字符串中的字符的例:

    #include <iostream>

    #include <string>

    using namespace std;

    int main(){

        string s = "abcDEF1234";

        for(int i=0,len=s.length(); i<len; i++){

            cout<<s[i]<<" ";

        }

        cout<<endl;

        s[4] = '6';

        cout<<s<<endl;

        return 0;

    }

     

    运行之,参见下图:

     

    ☆字符串的拼接

    有了 string 类,我们可以使用+或+=运算符来直接拼接字符串,非常方便,就不需要使用C语言中的 strcat()、strcpy()、malloc() 等函数来拼接字符串了,不用担心空间不够会溢出问题了。

    可以用+运算符来拼接字符串时,运算符的两边可以都是 string 字符串,也可以是一个 string 字符串和一个C风格的字符串,还可以是一个 string 字符串和一个字符数组,或者是一个 string 字符串和一个单独的字符。例:

    #include <iostream>

    #include <string>

    using namespace std;

    int main(){

        string s1 = "Hello ";

        string s2 = "World";

        char s3[] = "世界";

     

        string s5 = s1 + s2;

        string s6 = s1 + s3;

       

        cout<<s5<<endl<<s6<<endl;

       

        return 0;

    }

    运行输出如下:

     

    ☆string 字符串的增删改查

    C++ 提供的 string 类包含了若干实用的成员函数,大大方便了字符串的插入、删除、更改、查询等操作。

     

    插入子字符串函数

    insert (size_t pos, const string& str);

    pos 表示要插入的位置,也就是下标;str 表示要插入的字符串,它可以是 string 字符串,也可以是C风格的字符串。

    删除子字符串函数

    erase (size_t pos = 0, size_t len = npos);

    pos 表示要删除的子字符串的起始下标,len 表示要删除子字符串的长度。如果不指明 len 的话,那么直接删除从 pos 到字符串结束处的所有字符(此时 len = str.length - pos)。

    提取子字符串函数

    substr (size_t pos = 0, size_t len = npos);

    pos 为要提取的子字符串的起始下标,len 为要提取的子字符串的长度。

     

    字符串插入、删除、提取子字符串的例

    #include <iostream>

    #include <string>

    using namespace std;

    int main(){

        string s1, s2, s3, s4, s5;

        s1 ="1234567890";

        s2 = "aaa";

        s1.insert(5, s2); //插入字符串

        cout<< s1 <<endl;

     

        s3 ="1234567890";

        s3.erase(8); //删除字符串

        cout<< s3 <<endl;

     

        s4 ="1234567890";

        s5 = s4.substr(4, 3); //提取子字符串

        cout<< s5 <<endl;

     

        return 0;

    }

     

    运行输出如下:

     

    字符串查找

    string 类提供了几个与字符串查找有关的函数:find() 函数、rfind() 函数、find_first_of() 函数

    在此仅介绍find() 函数,其它可上网查阅。

    find()函数两种原型为:

    find (const string& str, size_t pos = 0)

    find (const char* s, size_t pos = 0)

    第一个参数为待查找的子字符串,它可以是 string 字符串,也可以是C风格的字符串。第二个参数为开始查找的位置(下标);如果不指明,则从第0个字符开始查找。

     

    find()函数的例子

    #include <iostream>

    #include <string>

    using namespace std;

    int main(){

        string s1 = "first second third";

        string s2 = "second";

        int index = s1.find(s2,5);

        if(index < s1.length())

            cout<<"Found at index : "<< index <<endl;

        else

            cout<<"Not found"<<endl;

        return 0;

    }

     

    运行输出如下:

     

     

     

     

     

    Processed: 0.013, SQL: 8