第3章 标准库类型

来源:互联网 发布:mac终端查看文件内容 编辑:程序博客网 时间:2024/06/04 23:32

3.1、命名空间的using声明

    在头文件中必须总是使用完全限定的标准库名字(即如std:cin)。因为如果在头文件中放置using声明,就相当于在包含该头文件的每个程序中都放置了同一using声明,不论该程序是否需要using声明。头文件中应该只定义确实必要的东西。

3.2、标准库string类型

3.2.1、string对象的定义和初始化

四种初始化方式:(1)strings1;默认构造函数,s1为空串;(2)strings2(s1);将s2初始化为s1的一个副本;(3)string s3(“value”);将s3初始化为一个字符串字面值副本;(4)strings4(n,’c’);将s4初始化为字符’c’的n个副本。

string s3("nnn");

string s4(3,'n');//两者均与nnn进行==比较,结果是1char a[4] = {'n','n','n'};也是1。用char[4]会在nnn后面自动补’\0’,如果设成char[3]后面会跟乱码。上述比较与java有区别(java有字符串常量和字符串变量之分,new出来的就不会跟常量相等,而且char[]不能与String比较)···

    由于历史原因以及为了与C语言兼容,字符串字面值与标准库string类型不是同一种类型。

3.2.2、string对象的读写

cin>>s;从标准输入读取string,并存入s中,读取特点有:(1)读取并忽略开头所有的空白字符(如空格、换行符、制表符);(2)读取字符直至再次遇到空白字符,读取终止。

    对于读入未知数目的string对象,用while(cin>>s){···}达到文件尾则跳出循环。

    用getline读取整行文本。该函数接受两个参数:一个输入流对象和一个string对象。getline函数从输入流的下一行读取,并保存到string中,但不包括换行符。并且它与cin不同,不忽略开头的换行符。如果第一个就是换行符,则getline的string被置为空。如while(getline(cin,s)){···}。java是s=bufferedReader.readLine();方法不用传参数~。

3.2.3、string对象的操作

    c++是size求字符个数(不考虑末尾的‘\0’字符,"nnn\0"这样长度还是3)(java是length()方法,"nnn\0"这样长度是4)。s.empty()表示如果s为空串,则返回true,否则返回false。

    size()操作返回的是string::size_type类型的值,它定义为与unsigned型具有相同的含义并且可以保证足够大能存储任意string对象的长度。用法如:string::size_type m = s3.size();任何存储string的size操作结果的变量必须为string::size_type类型,而不要将返回值赋给int变量(防溢出)。

       两个string对象相等(==)是指他们的长度相同且含有相同的字符(java的==判断字符串是判断是否是引用同一个内容,而new出来的,长度字符都相等也显示false,得用equal)。(<、<=、>、>=)比较策略:(1)如果两个string对象长度不同且短的和长的字符对象前面部分匹配,则长的string对象长;(2)如果两个string对象的字符不同,则比较第一个不匹配的字符。

       string对象的赋值(=,如st1 = st2)所做的工作必须先把st1占用的相关内存释放掉,然后再分配给st1足够存放st2副本的内存空间,最后把st2中的所有字符复制到新分配的内存空间。

       string对象相加(+、+=)用于连接两字符串,也可以将string对象和字符串字面值(就是字符串常量,直接显示”字符串内容”)混合连接得到同样的结果。string s = “hi”+”,”+s1是错误的,第一个“+”表达式将两个字面值连接起来,这是不允许的。而string s = s1+”hi”+”,”则是对的,因为事实上后一个加的前面是string tmp = s1+”hi”,并不是字符串字面值。

       string对象的下标从0开始(尝试),如string str(“some”);str[0]为s。可以像str[0] ='*';将第一个字符串元素赋值为别的。任何可产生整数值的表达式都可用做下标操作符的索引,如str[1*2] = ‘*’将第三个元素赋为*。

3.2.4、string对象中字符的处理

       对string对象中的单个字符进行处理(是否为空白符、字母、数字等),这些函数在cctype头文件中定义。可打印的字符是指那些可以显示表示的字符;空白字符表示空格、制表符、垂直制表符、回车符、换行符和进纸符的任意一种;标点符号表示除了数字、字母或空白字符以外的其他可打印字符。C标准库中有ctype.h头文件。

3.3、标准库vector类型

#include<vector>

using std::vector;

vector是类模板。

3.3.1、vector对象的定义和初始化

    构造函数:(1)vector<T> v1;vector保存类型为T的对象。默认构造函数,v1为空;(2)vector<T> v2(v1);v2是v1的一个副本;(3)vector<T> v3(n,i);v3包含n个值为i(得是T类型)的元素。(4)vector<T> v4(n);v4含有值初始化的元素的n个副本。

    vector对象可以在运行时高效地添加元素。(而对于java早期的Vector类的所有方法是同步式的方法,因此对于无需同步操作时,要浪费很多时间。C++的vector不是同步的)。

    如果没有指定元素的初始化式,那么标准库将自行提供一个元素初始值进行值初始化

3.3.2、vector对象的操作

    vector对象的size类似于string类型,size返回相应vector类定义的size_type的值,vector类型总是包含vector的元素类型:如,vector<int>::size_type

    push_back()操作(之前一直纳闷为啥这么命名):也就是“插入(push)”到vector对象的“后面(back)”。

    vector的下标操作,vector元素的位置从0开始。如for循环:for(vector<int>::size_type ix = 0;ix!=ivec.size(); ++ix){ivec[ix] = 0;}

    关于上述“!=”习惯是合理的(需要学习泛型编程才能体会)。

    没有事先记录size返回值而是直接在for循环中调用size()方法反映一种良好的编程习惯。因为循环中很可能导致vector元素的增减,直接调用size()就不怕vector长的变量过期了。

    下标操作不添加元素(如对空vector<int> vc执行vc[0]=1是错误的不会添加元素,得用push_back()方法),必须是已存在的元素才能用下标操作符进行索引。通过下标操作进行赋值时,不会添加任何元素。试图对不存在的元素进行下标操作是程序设计过程中常犯的严重错误。所谓的“缓冲区溢出”错误就是对不存在的元素进行下标操作的结果。(与下面摘抄的无冲突,看似是内存访问越界,其实还带有“覆盖”在里面)

    网上摘抄:内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足

需求,于是产生溢出(如new之后忘记delete)。内存访问越界,简单的说,你向系统申请了一块内存,在使用这块内存的时候,超出了你申请的范围。缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量,溢出的数据覆盖在合法数据上。栈溢出就是缓冲区溢出的一种。

3.4、迭代器简介

    vector<int>::iterator iter;(尖括号中int是看vector存的元素决定)每种容器都定义了一对命名为begin和end函数用于返回迭代器。由end操作返回的迭代器指向vector的“末端元素的下一个”。通常称为超出末端迭代器(off-the-enditerator)。表明它指向一个不存在的元素,只是起了哨兵的作用。如果vector为空,begin返回的迭代器与end返回的迭代器相同。迭代器可以用解引用操作符(*操作符)来访问迭代器所指向的元素,如*iter。(注:由于end操作返回的迭代器不指向任何元素,因此不能对它进行解引用或自增操作)。迭代器操作样例:

for(vector<int>::iterator iter = ivec.begin();iter!= ivec.end();++iter)*iter=0;

    const_iterator(如,vector<string>::const_iterator iter),在解引用时可以得到一个指向const对象的引用,这样借助*想修改所指向的内容则不允许。即我们得到一个迭代器,它自身的值可以改变,但不能用来改变其所指向的元素值。注:常量迭代器(如,constvector<int>::iterator iter),声明一个const迭代器时,必须初始化迭代器,一旦被初始化后,就不能改变它的值(即本身的值,但该常量迭代器指向的值可以改变)。还有如constvector<int> nines(10,9);则不可以改变vector中的元素值。(附加:对于java的final变量是不可改变的,但它的值可以在运行时刻初始化,也可以在编译时刻初始化,甚至可以放在构造函数中初始化,而不必在声明的时候初始化)。

    迭代器的算术操作:iter1-iter2用来计算两个迭代器对象的距离,该距离是名为difference_typesigned类型的值(因为可能为负),该类型可以保证足够大以存储任何两个迭代器对象间的距离。iter1和iter2两者必须都指向同一vector中的元素或者指向vector末端之后的下一个元素(迭代器加法也一样,结果指向元素或者末尾的下一个元素)。(任何改变vector长度的操作都会使已存在的迭代器失效,例如在push_back后,就不能再信赖指向vector的迭代器值了)。

    不能用(ivec.begin()+ivec.end())/2求中间值。end指向的是最后一个元素的下一个,对于VS编译器,上述的+没有定义,编译时就错了。

3.5、标准库bitset类型

#include<bitset> usingstd:bitset;

3.5.1、bitset对象的定义和初始化

    如bitset<17>bitvec;尖括号中的长度值定义为整型字面值常量或是已用常量值初始化的整型的const对象(即在编译时就得知道长度)。

    初始化bitset对象的方法:(1)bitset<n>b;b有n位,每位都是0;(2)bitset<n> b(u);b是unsigned longu的一个副本;(3)bitset<n>b(s);b是string对象s中含有的位串的副本;(4)bitset<n> b(s,pos,n);b是s(s只能是string不能是unsigned long型)中从位置pos开始的n个位的副本。

    用unsigned值初始化bitset对象:该unsigned long型将转化为二进制的位模式。长度不够则高阶位被丢弃,否则高阶位补0。

    string对象初始化bitset对象:从string对象读入位集的顺序是从右向左。即string对象的最右边字符用来初始化bitset对象的低阶位(即下标为0的位)。可以想成是直接将string搬过来(即如1100->1100bitset)一样。(而unsigned则是1100->0011bitset)。

3.5.2、bitset对象上的操作

    count()操作返回置为1的二进制位的个数:size_t bits_set = bitvec.count();size_t(vector中是size_type)类型定义在cstddef头文件中,该文件是C标准库的头文件stddef.h的C++版本。它是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。其size()返回的类型也是size_t。

    访问bit对象中的位:可以用下标操作符来读或写某个索引位置的二进制位。如测试某个二进制位是否为1,bitvec.test(i)等价于bitvec[i]。对个别位取反bitvec.flip(i)等价于bitvec[i].flip();bitvec.flip()为对所有位取反。

    获取bitset对象的值:to_ulong操作返回一个unsigned long值,该值与bitset对象的位模式存储值相同。仅当bitset类型的长度小于或等于unsigned long的长度时,才可以使用to_ulong操作(超出,运行时会出错,unsigned int/long 0~4294967295;long long的最大值:9223372036854775807)。bitset用到了位操作符。
原创粉丝点击