C++ Primer 读书笔记 标准库类型

本文详细介绍了C++标准库中的三种重要类型:string、vector和bitset。分别讲述了这些类型的使用方法、初始化方式以及常见操作,并提供了示例代码帮助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

这一章主要介绍了三个重要的标准库类型stringvectorbitset类型。

 

标准库string类型

 

string类型支持长度可变的字符串。下面是几种初始化string对象的方式:

string s1;       //默认构造函数,s1为空串

string s2(s1);    //s2初始化为s1的一个副本

string s3(“value”); //s3初始化为一个字符串字面值的副本

string s4(n, ‘c’);   //s4初始化为字符’c’n个副本

 

在使用string类型之前,要包含string头文件(#include <string>)using std::string

可以从标准输入中读取string对象,并把读入的串存储在string对象中,有两个规则:

1、读取并忽略开关所有的空白字符(如空格、换行符、制表符)。

2、读取字符直到再次遇到空白字符,读取终止。

如果你想读取整行输入文本,可以使用getline函数。getline函数接受两个参数:一个输入流对象和一个string对象。

下面列出了常用的string对象操作:

 

s.empty()          如果s为空串,则返回true,否则返回false

s.size()               返回s中字符的个数,包括空字符(空格、换行符、制表符等)

s[n]                     返回s中位置为n的字符,位置从0开始计数,即s[0]返回s的第一个字符

s1 + s2               s1s2连接成一个新字符串,返回新生成的字符串

s1 = s2               s1的内容替换为s2的副本

s1 == s2             比较s1s2的内容,相等则返回true,否则返回false

!=, <, <=, >, >= 保持这些关系操作符惯有的含义

 

这里要注意的是,任何存储s.size()操作结果的变量必须为string::size_type类型,它是由string类定义的一种特殊类型,可以保证足够大能够存储任意string对象的长度。特别重要的是,不要把size()的返回值赋给一个int变量。

String对象的下标从0开始,如果s是一个string对象且s不空,则s[0]就是字符串的第一个字符,s[1]就表示第二个字符(如果有的话),而s[s.size() - 1]则表示s的最后一个字符。引用下标时如果超出下标作用范围就会引起溢出错误。

关系操作符比较两个string对象是采用了和(大小写敏感的)字典排序相同的策略:

1、              如果两个string对象长度不同,且短的string对象与长的string对象的前面部分相匹配,则短的string对象小于长的string对象。

2、              如果两个string对象的字符不同,则比较第一个不匹配的字符。

我们经常要对string对象中的单个字符进行处理。下面是cctype头文件中字义的处理字符的函数:

isalnum(c)         如果c是字母或数字,则返回true

isalpha(c)          如果c是字母,则返回true

iscntrl(c)            如果c是控制字符,则返回true

isdigit(c)            如果c是数字,则返回true

isgraph(c)                   如果c不是空格,但可打印,则返回true

islower(c)        如果c是小写字母,则返回true

isprint(c)           如果c是可打印字符,则返回true

ispunct(c)                   如果c是标点符号,则返回true

isspace(c)                   如果c是空白字符,则返回true

isupper(c)         如果c是大字字母,则返回true

isxdigit(c)          如果c是十六进制数,则返回true

tolower(c)         如果c是大字字母,则返回其小写字母形式,否则直接返回c

toupper(c)        如果c是小字字母,则返回其大写字母形式,否则直接返回c

 

我编写了一个小程序来加深对上面这些内容的理解:

#include <iostream>

#include <string>

using namespace std;

int main()

{

    string s1;  // 默认s1为空

    string s2("test");  // s2初始化为字符串"test"的副本

    string s3(s2);  // s3初始化为s2的副本,此时s3保存的字符串就是"test"

    string s4(5,'t');   // s4初始化为字符't'的5个副本,即字符串"ttttt"

    // 下面我们将s1 s2 s3 s4的值以及长度输出到屏幕

    if(s1.empty()){

        cout << "s1 is empty!" << endl;

    }

    cout << "s1 : " << s1 << "/tthe size is " << s1.size()

        << "/ns2 : " << s2 << "/tthe size is " << s2.size()

        << "/ns3 : " << s3 << "/tthe size is " << s3.size()

        << "/ns4 : " << s4 << "/tthe size is " << s4.size() << endl;

    // 交换s3s4的内容

    string temp(s3);

    s3 = s4;

    s4 = temp;

    // 接下来提示用户输入字符串,并把用户输入的字符串保存到s1s2

    cout << "Please input some words :" << endl;

    cin >> s1;

    getline(cin,s2);

    // 再次把s1 s2 s3 s4 输出到屏幕,查看结果,注意s1s2的区别

    cout << "s1 : " << s1 << "/tthe size is " << s1.size()

        << "/ns2 : " << s2 << "/tthe size is " << s2.size()

        << "/ns3 : " << s3 << "/tthe size is " << s3.size()

        << "/ns4 : " << s4 << "/tthe size is " << s4.size() << endl;

    return 0;

}

执行程序时,我输入的是“how are you!,运行结果如下图:

思考:保存用户输入的时候,为什么s1只保存了how,s2却没有保存how ?

 

 

标准vector类型

 

我们把vector称为容器,它可以包含其他对象,但是一个容器(vector)中的所有对象都必须是同一种类型的。

vector对象的定义和初始化有以下几种方式:

 

vector<T> v1;       // vector保存类型为T的对象,默认构造函数v1为空

vector<T> v2(v1);   // v2v1的一个副本

vector<T> v3(n, i); // v3包含n个值为i的元素

vector<T> v4(n);    // v4含有值初始化的元素的n 个副本

 

在使用vector之前,要#include <vector>using std::vector

vector对象(以及其它标准库容器对象)的重要属性就在于可以在运行时高效地添加元素。因为vector增长的效率高,在元素值已知的情况下,最好是动态地添加元素。下面是一些vector对象的操作:

 

v.empty();      // 如果v为空,则返回true,否则返回false

v.size();       // 返回v中元素的个数,vector<T>::size_type类型

v.push_back(t)  // v的末尾增加一个值为t的元素

v[n]            // 返回v中位置为n的元素

v1 = v2         // v1的元素替换为v2中元素的副本

v1 == v2        // 如果v1v2相等,则返回true

!=, <, <=, >, >=    // 保持这些关系操作符惯有的含义

 

vector中的对象是没有命名的,可以按vector中对象的位置来访问它们,即通过使用下标操作来获取或更改元素,但是不能用下标操作来添加元素。

标准库提供的另一种访问元素的方法是使用迭代器(iterator)Iterator是一种检查容器内元素并遍历元素的数据类型。因为迭代器对所有的容器都适用,现代C++程序更倾向于使用迭代器而不是下标操作访问容器元素,即使对支持下标操作的vector类型也是这样。

每种容器都定义了一对命名为beginend的函数,用于返回迭代器。如果容器中有元素的话,由begin返回的迭代器指向第一个元素,由end返回的迭代器指向vector的“末端元素的下一个”,通常称为超出末端迭代器,表明它指向了一个不存在的元素。如果vector为空,beginend返回的迭代器相同。迭代器的解引用操作符*返回迭代器当前所指向的元素。每种容器类型还定义了一种名为const_iterator的类型,该类型只能用于读取容器内元素,但不能改变其值。

 

动手做:自己编写程序,加深对vector的理解,下面是我写的一个小程序

#include <iostream>

#include <string>

#include <vector>

 

using namespace std;

 

int main()

{

    //--------------------------------------------------

    // 这段代码的功能是用一个容器保存用户输入的单词

    //--------------------------------------------------

 

    string word;

 

    // 定义一个string类型的容器

    vector<string> text;

    // 指示用户输入单词,按回车结束输入

    cout << "Please input your words:/n(press enter as end)" << endl; 

    while ( cin.peek() != '/n' && cin >> word ){

        text.push_back(word);       // 保存用户输入的单词

    }

    // 遍历text容器,把保存的单词输出到屏幕

    if(text.empty()){     // 如果容器为空,即用户没有输入任何单词

        cout << "You have not input any words!" << endl;

    }

    else{       // 把用户输入的单词输出到屏幕,并统计单词个数

        cout << "There are the words you input:" << endl;

        // 用户输入的单词不允许被修改,这里定义一个const_iterator

        for (vector<string>::const_iterator iter = text.begin();

            iter != text.end(); ++iter ){

            cout << *iter << " ";

        }

        cout << "/nand there are " << text.size() << " words!" << endl;

    }

 

 

    //----------------------------------------------------

    // 下面这段代码的功能是对用户输入的数字按从小到大排序

    //----------------------------------------------------

 

    int num;

 

    // 定义一个int类型的容器

    vector<int> ivec;

    cout << "Please input the numbers you want to sort:"

        "/n(press enter as end)" << endl;

    cin.clear();

    cin.ignore(); // 清空输入流缓冲区

    while( cin.peek() != '/n' && cin >> num ){

        ivec.push_back( num );

    }

    if( ivec.empty()){

        cout << "You have not input any numbers!" << endl;

    }

    else{

        cout << "There are the numbers you input:" << endl;

        vector<int>::iterator iter;  

        for( iter = ivec.begin(); iter != ivec.end(); ++ iter){

            cout << *iter << " ";

        }

        cout << "/nBy sort ascending:" << endl;

 

        // 用插入排序法对容器内的元素排序

        vector<int>::iterator tempiter;   // 定义一个iterator(思考为什么不是const_iterator)

        for( iter = ivec.begin() + 1; iter != ivec.end(); ++ iter){

            num = *iter;

            tempiter = iter;

            while( tempiter != ivec.begin() && *(tempiter - 1) > num){

                *tempiter = *(tempiter - 1);

                -- tempiter;

            }

            *tempiter = num;

        }

        // 输出排序后的容器

        for( iter = ivec.begin(); iter != ivec.end(); ++ iter){

            cout << *iter << " ";

        }

        cout << endl;

    }

    return 0;

}

运行结果如下图:

 

思考:修改程序,用下标操作实现程序的功能。说说下标操作和迭代器有什么区别?

注意:标准库vector类型中并没有定义输出到os流的操作,任何试图通过容器名输出容器内容的操作都是错误的,例如cout << ivec;就是错误的。

 

 

标准库bitset类型

 

bitset类型提供了对二进制位的有序集的操作方法。下面是初始化bitset对象的方法:

 

bitset<n> b;        // bn位,每位都为0

bitset<n> b(u);     // bunsigned longu的一个副本

bitset<n> b(s);     // bstring对象s中含有的位串的副本

bitset<n> b(s,pos,n);// bs中从位置pos开始的n个位的副本

 

同样,在使用bitset之前,要#include <bitset>using std::bitset

值得注意的是,当用unsigned long值作为bitset对象的初始值是,该值将转化为二进制的位模式保存在bitset对象中。如果bitset类型长度n大于unsigned long值的二进制位数,则其余的高阶位将置为0;如果bitset类型长度n小于unsigned long值的二进制位数,则只使用unsigned值中的低阶位,超过bitset类型长度的高阶位将被丢弃。

特别要注意的是,当用string对象初始化bitset对象时,string对象直接表示为位模式,从string对象读入位集的顺序是从右向左。即string对象和bitset对象之间是反向转化的:string对象的最右边字符(即下标最大的那个字符)用来初始化bitset对象的低阶位(即下标为0的位)。同时还要注意,string字符串只能是包含01的字符串,含有其它字符,将出现错误。

下面是一些bitset常用的操作:

 

b.any()         如果b中存在值为1的二进制位,则返回true

b.none()        如果b中不存在值为1的二进制位,则返回true

b.count()       返回b中值为1的二进制位的个数

b.size()        返回b中二进制位的位数

b[pos]          访问b中在pos处的二进制位

b.test(pos)     如果b中在pos处的二进制位是1,则返回true

b.set()         b中所有二进制位都置为1

b.set(pos)      b中在pos处的二进制位置为1

b.reset()       b中所有二进制位都置为0

b.reset(pos)    b中在pos处的二进制位置0

b.flip()        b中所有二进制位逐位取反

b.flip(pos)     b中在pos处的二进制位取反

b.to_ulong()    b中同样的二进制位返回一个unsigned long

os << b         b中的位集输出到os

 

其中b.size()操作的返回值类型是标准库中命名为size_t的类型。size_t类型定义在cstddef头文件中,它是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值