std:string学习

之所以抛弃 char* 的字符串而选用 C++ 标准程序库中的 string 类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下 ( 甚至是 100%) 的需要。我们可以用 = 进行赋值操作, == 进行比较, + 做串联(是不是很简单 ? )。我们尽可以把它看成是 C++ 的基本数据类型。
    好了,进入正题 ………
首先,为了在我们的程序中使用 string 类型,我们必须包含头文件 。如下:
   #include // 注意这里不是 string.h string.h 是 C 字符串头文件

1 .声明一个 C++ 字符串
声明一个字符串变量很简单:
   string Str;
这样我们就声明了一个字符串变量,但既然是一个类,就有构造函数和析构函数。上面的声明没有传入参数,所以就直接使用了 string 的默认的构造函数,这个函数所作的就是把 Str 初始化为一个空字符串。 String 类的构造函数和析构函数如下:
a)    string s;  // 生成一个空字符串 s
b)    string s(str) // 拷贝构造函数 生成 str 的复制品
c)    string s(chars,stridx) // 将字符数组 chars 内 “ 始于位置 stridx” 的部分当作字符串的初值
d)    string s(str,stridx,strlen) // 将字符串 str 内 “ 始于 stridx 且长度顶多 strlen” 的部分作为字符串的初值
e)    string s(cstr) // 将 C 字符串作为 s 的初值
f)    string s(chars,chars_len) // 将 C 字符串前 chars_len 个字符作为字符串 s 的初值。
g)    string s(num,c) // 生成一个字符串,包含 num 个 c 字符
h)    string s(beg,end) // 以区间 beg;end( 不包含 end) 内的字符作为字符串 s 的初值
i)    s.~string() // 销毁所有字符,释放内存
都很简单,我就不解释了。
2 .字符串操作函数
    这里是 C++ 字符串的重点,我先把各种操作函数罗列出来,不喜欢把所有函数都看完的人可以在这里找自己喜欢的函数,再到后面看他的详细解释。
a) =,assign()   // 赋以新值
b) swap()   // 交换两个字符串的内容
c) +=,append()// 在尾部添加字符
d) insert() // 插入字符
e) erase() // 删除字符
g) replace() // 替换字符
h) + // 串联字符串
i) ==,!=,<,<=,>,>=,compare()  // 比较字符串
j) size(),length()  // 返回字符数量
k) max_size() // 返回字符的可能最大个数
l) empty()  // 判断字符串是否为空
m) capacity() // 返回重新分配之前的字符容量
n) reserve() // 保留一定量内存以容纳一定数量的字符
o) [ ], at() // 存取单一字符
r) copy() // 将某值赋值为一个 C_string
s) c_str() // 将内容以 C_string 返回
t) data() // 将内容以字符数组形式返回
u) substr() // 返回某个子字符串
v) 查找函数
w)begin() end() // 提供类似 STL 的迭代器支持
x) rbegin() rend() // 逆向迭代器
y) get_allocator() // 返回配置器
下面详细介绍:
2 . 1 C ++ 字符串和 C 字符串的转换
   C++ 提供的由 C++ 字符串得到对应的 C_string 的方法是使用 data() 、 c_str() 和 copy() ,其中, data() 以字符数组的形式返回字符串内容,但并不添加 ’\0’ 。 c_str() 返回一个以 ‘\0’ 结尾的字符数组,而 copy() 则把字符串的内容复制或写入既有的 c_string 或字符数组内。 C++ 字符串并不以 ’\0’ 结尾。我的建议是在程序中能使用 C++ 字符串就使用,除非万不得已不选用 c_string 。由于只是简单介绍,详细介绍掠过,谁想进一步了解使用中的注意事项可以给我留言 ( 到我的收件箱 ) 。我详细解释。
2 . 2 大小和容量函数
    一个 C++ 字符串存在三种大小: a) 现有的字符数,函数是 size() 和 length() ,他们等效。 Empty() 用来检查字符串是否为空。 b)max_size() 这个大小是指当前 C++ 字符串最多能包含的字符数,很可能和机器本身的限制或者字符串所在位置连续内存的大小有关系。我们一般情况下不用关心他,应该大小足够我们用的。但是不够用的话,会抛出 length_error 异常 c)capacity() 重新分配内存之前 string 所能包含的最大字符数。这里另一个需要指出的是 reserve() 函数,这个函数为 string 重新分配内存。重新分配的大小由其参数决定,默认参数为 0 ,这时候会对 string 进行非强制性缩减。

还有必要再重复一下 C++ 字符串和 C 字符串转换的问题,许多人会遇到这样的问题,自己做的程序要调用别人的函数、类什么的(比如数据库连接函数 Connect(char*,char*) ),但别人的函数参数用的是 char* 形式的,而我们知道, c_str() 、 data() 返回的字符数组由该字符串拥有,所以是一种 const char*, 要想作为上面提及的函数的参数,还必须拷贝到一个 char*, 而我们的原则是能不使用 C 字符串就不使用。那么,这时候我们的处理方式是:如果此函数对参数 ( 也就是 char*) 的内容不修改的话,我们可以这样 Connect((char*)UserID.c_str(), (char*)PassWD.c_str()), 但是这时候是存在危险的,因为这样转换后的字符串其实是可以修改的(有兴趣地可以自己试一试),所以我强调除非函数调用的时候不对参数进行修改,否则必须拷贝到一个 char* 上去。当然,更稳妥的办法是无论什么情况都拷贝到一个 char* 上去。同时我们也祈祷现在仍然使用 C 字符串进行编程的高手们(说他们是高手一点儿也不为过,也许在我们还穿开裆裤的时候他们就开始编程了,哈哈 … )写的函数都比较规范,那样我们就不必进行强制转换了。

2 . 3 元素存取
    我们可以使用下标操作符 [] 和函数 at() 对元素包含的字符进行访问。但是应该注意的是操作符 [] 并不检查索引是否有效(有效索引 0~str.length() ),如果索引失效,会引起未定义的行为。而 at() 会检查,如果使用 at() 的时候索引无效,会抛出 out_of_range 异常。
    有一个例外不得不说, const string a; 的操作符 [] 对索引值是 a.length() 仍然有效,其返回值是 ’\0’ 。其他的各种情况, a.length() 索引都是无效的。举例如下:
const string Cstr(“const string”);
string Str(“string”);

Str[3];    //ok
Str.at(3);  //ok

Str[100]; // 未定义的行为
Str.at(100);  //throw out_of_range

Str[Str.length()]  // 未定义行为
Cstr[Cstr.length()] // 返回 ‘\0’
Str.at(Str.length());//throw out_of_range
Cstr.at(Cstr.length()) throw out_of_range

我不赞成类似于下面的引用或指针赋值:
char& r=s[2];
char* p= &s[3];
因为一旦发生重新分配, r,p 立即失效。避免的方法就是不使用。

2 . 4 比较函数
   C++ 字符串支持常见的比较操作符( >,>=,<,<=,==,!= ),甚至支持 string 与 C-string 的比较 ( 如 str<”hello”) 。在使用 >,>=,<,<= 这些操作符的时候是根据 “ 当前字符特性 ” 将字符按字典顺序进行逐一得比较。字典排序靠前的字符小,比较的顺序是从前向后比较,遇到不相等的字符就按这个位置上的两个字符的比较结果确定两个字符串的大小。同时, string(“aaaa”)     另一个功能强大的比较函数是成员函数 compare() 。他支持多参数处理,支持用索引值和长度定位子串来进行比较。他返回一个整数来表示比较结果,返回值意义如下: 0- 相等 〉 0- 大于 <0- 小于。举例如下:
   string s(“abcd”);
   
   s.compare(“abcd”); // 返回 0
   s.compare(“dcba”); // 返回一个小于 0 的值
   s.compare(“ab”); // 返回大于 0 的值
   
s.compare(s); // 相等
   s.compare(0,2,s,2,2); // 用 ”ab” 和 ”cd” 进行比较 小于零
   s.compare(1,2,”bcx”,2); // 用 ”bc” 和 ”bc” 比较。
怎么样?功能够全的吧!什么?还不能满足你的胃口?好吧,那等着,后面有更个性化的比较算法。先给个提示,使用的是 STL 的比较算法。什么?对 STL 一窍不通?靠,你重修吧!

2 . 5 更改内容
这在字符串的操作中占了很大一部分。
首先讲赋值,第一个赋值方法当然是使用操作符 = ,新值可以是 string( 如: s=ns) 、 c_string( 如: s=”gaint”) 甚至单一字符(如: s=’j’ )。还可以使用成员函数 assign() ,这个成员函数可以使你更灵活的对字符串赋值。还是举例说明吧:
s.assign(str); // 不说
s.assign(str,1,3);// 如果 str 是 ”iamangel” 就是把 ”ama” 赋给字符串
s.assign(str,2,string::npos);// 把字符串 str 从索引值 2 开始到结尾赋给 s
s.assign(“gaint”); // 不说
s.assign(“nico”,5);// 把 ’n’ ‘I’ ‘c’ ‘o’ ‘\0’ 赋给字符串
s.assign(5,’x’);// 把五个 x 赋给字符串
把字符串清空的方法有三个: s=””;s.clear();s.erase();( 我越来越觉得举例比说话让别人容易懂! ) 。
string 提供了很多函数用于插入( insert )、删除( erase )、替换( replace )、增加字符。
先说增加字符(这里说的增加是在尾巴上),函数有 += 、 append() 。举例如下:
s+=str;// 加个字符串
s+=”my name is jiayp”;// 加个 C 字符串
s+=’a’;// 加个字符

s.append(str);
s.append(str,1,3);// 不解释了 同前面的函数参数 assign 的解释
s.append(str,2,string::npos)// 不解释了

s.append(“my name is jiayp”);
s.append(“nico”,5);
s.append(5,’x’);

 

字符串操作是一个不小的主题,在标准C++中,string字符串类成为一个标准,之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下的需要.
    下面我们首先从一些示例开始学习下string类的使用.
1)
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s("hehe");
    cout<<s<<endl;
    cin.get();
}
2)
#include <string>
#include <iostream>
using namespace std;

void main()
{
    char chs[] = "hehe";
    string s(chs);
    cout<<s<<endl;
    cin.get();
}
3)
#include <string>
#include <iostream>
using namespace std;

void main()
{
    char chs[] = "hehe";
    string s(chs,1,3);    //指定从chs的索引1开始,最后复制3个字节
    cout<<s<<endl;
    cin.get();
}
4)
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s1("hehe");
    string s2(s1);   
    cout<<s2<<endl;
    cin.get();
}
5)
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s1("hehe",2,3);
    string s2(s1);   
    cout<<s2<<endl;
    cin.get();
}
6)
#include <string>
#include <iostream>
using namespace std;

void main()
{
    char chs[] = "hehe";
    string s(chs,3);    //将chs前3个字符作为初值构造
    cout<<s<<endl;
    cin.get();
}
7)
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s(10,'k');    //分配10个字符,初值都是'k'
    cout<<s<<endl;
    cin.get();
}
//以上是string类实例的构造手段,都很简单.

9)
//赋新值
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s(10,'k');    //分配10个字符,初值都是'k'
    cout<<s<<endl;
    s = "hehehehe";
    cout<<s<<endl;
    s.assign("kdje");
    cout<<s<<endl;
    s.assign("fkdhfkdfd",5);    //重新分配指定字符串的前5的元素内容
    cout<<s<<endl;       
    cin.get();
}
10)
//swap方法交换
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s1 = "hehe";
    string s2 = "gagaga";
    cout<<"s1 : "<<s1<<endl;
    cout<<"s2 : "<<s2<<endl;
    s1.swap(s2);
    cout<<"s1 : "<<s1<<endl;
    cout<<"s2 : "<<s2<<endl;
    cin.get();
}
11)
//+=,append(),push_back()在尾部添加字符
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "hehe";
    s += "gaga";
    cout<<s<<endl;
    s.append("嘿嘿");    //append()方法可以添加字符串
    cout<<s<<endl;
    s.push_back('k');    //push_back()方法只能添加一个字符...
    cout<<s<<endl;
    cin.get();
}
12)
//insert() 插入字符.其实,insert运用好,与其他的插入操作是一样的.
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "hehe";
    s.insert(0,"头部");            //在头部插入
    s.insert(s.size(),"尾部");    //在尾部插入
    s.insert(s.size()/2,"中间");//在中间插入
    cout<<s<<endl;
    cin.get();
}
13)
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "abcdefg";
    s.erase(0,1);    //从索引0到索引1,即删除掉了'a'
    cout<<s<<endl;
    //其实,还可以使用replace方法来执行删除操作
    s.replace(2,3,"");//即将指定范围内的字符替换成"",即变相删除了
    cout<<s<<endl;
    cin.get();
}

14)
//clear() 删除全部字符
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "abcdefg";
    cout<<s.length()<<endl;
    s.clear();
    cout<<s.length()<<endl;
    //使用earse方法变相全删除
    s = "dkjfd";
    cout<<s.length()<<endl;
    s.erase(0,s.length());
    cout<<s.length()<<endl;

    cin.get();
}
15)
//replace() 替换字符
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "abcdefg";
    s.replace(2,3,"!!!!!");//从索引2开始3个字节的字符全替换成"!!!!!"
    cout<<s<<endl;
    cin.get();
}
16)
//==,!=,<,<=,>,>=,compare()  比较字符串
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s1 = "abcdefg";
    string s2 = "abcdefg";   
    if (s1==s2)cout<<"s1 == s2"<<endl;
    else cout<<"s1 != s2"<<endl;
   
    if (s1!=s2)cout<<"s1 != s2"<<endl;
    else cout<<"s1 == s2"<<endl;
   
    if (s1>s2)cout<<"s1 > s2"<<endl;
    else cout<<"s1 <= s2"<<endl;
   
    if (s1<=s2)cout<<"s1 <= s2"<<endl;
    else cout<<"s1 > s2"<<endl;

    cin.get();
}
17)
//size(),length()  返回字符数量
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "abcdefg";
    cout<<s.size()<<endl;
    cout<<s.length()<<endl;

    cin.get();
}
18)
//max_size() 返回字符的可能最大个数
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "abcdefg";
    cout<<s.max_size()<<endl;

    cin.get();
}
19)
//empty()  判断字符串是否为空
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s ;
    if (s.empty())
        cout<<"s 为空."<<endl;
    else
        cout<<"s 不为空."<<endl;

    s = s + "abcdefg";
    if (s.empty())
        cout<<"s 为空."<<endl;
    else
        cout<<"s 不为空."<<endl;

    cin.get();
}
20)
// [ ], at() 存取单一字符
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "abcdefg1111";
   
    cout<<"use []:"<<endl;
    for(int i=0; i<s.length(); i++)
    {
        cout<<s[i]<<endl;
    }
    cout<<endl;

    cout<<"use at():"<<endl;
    for(int i=0; i<s.length(); i++)
    {
        cout<<s.at(i)<<endl;
    }
    cout<<endl;
   
    cin.get();
}
21)
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "abcdefg1111";
   
    const char * chs1 = s.c_str();
    const char * chs2 = s.data();

    cout<<"use at():"<<endl;
    int i;
    for(i=0; i<s.length(); i++)
    {
        cout<<"c_str() : "<<chs1[i]<<endl;
        cout<<"data() : "<<chs2[i]<<endl;
    }
    cout<<"c_str() : "<<chs1<<endl;
    cout<<"data() : "<<chs2<<endl;
    cout<<endl;
   
    cin.get();
}
22)
// substr() 返回某个子字符串
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "abcdefg1111";
   
    string str = s.substr(5,3);//从索引5开始3个字节
    cout<<str<<endl;
   
    cin.get();
}
23)
// find 查找函数
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "abcdefg1111";
    string pattern = "fg";
    string::size_type pos;
    pos = s.find(pattern,0);        //从索引0开始,查找符合字符串"f"的头索引
    cout<<pos<<endl;
    string str = s.substr(pos,pattern.size());
    cout<<str<<endl;
    cin.get();
}
24)
// begin() end() 提供类似STL的迭代器支持
#include <string>
#include <iostream>
using namespace std;

void main()
{
    string s = "abcdefg1111";
    for(string::iterator iter = s.begin(); iter!=s.end(); iter++)
    {
        cout<<*iter<<endl;
    }
    cout<<endl;

    cin.get();
}
        一个C++字符串存在三种大小:a)现有的字符数,函数是size()和length(),他们等效。 Empty()用来检查字符串是否为空。b)max_size() 这个大小是指当前C++字符串最多能包含的字符数,很可能和机器本身的限制或者字符串所在位置连续内存的大小有关系。我们一般情况下不用关心他,应该大小足够我们用的。但是不够用的话,会抛出length_error异常c)capacity()重新分配内存之前 string所能包含的最大字符数。这里另一个需要指出的是reserve()函数,这个函数为string重新分配内存。重新分配的大小由其参数决定,默认参数为0,这时候会对string进行非强制性缩减

 

 

1、“string s(str,stridx) 将字符串str内"始于位置stridx"的部分当作字符串的初值”。我发现str为string类型时不能正常运行,但为字符数组时却可以!这是为什么?

2、“string s8(beg,end) 以区间beg;end(不包含end)内的字符作为字符串s的初值”还有这个怎么用,可以举个例子吗?

3、 ”capacity() //返回重新分配之前的字符容量“是什么意思?

4、p) >>,getline() //从stream读取某值

   q) << //将谋值写入stream

    这两个怎么用??

希望上面四个问题能得到大虾们的解答!!

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页