C++学习笔记(三)

来源:互联网 发布:搜房网软件 编辑:程序博客网 时间:2024/06/05 17:38

第三章 字符串、向量和数组

1.两种最重要的标准库类型:string 和 vector。前者表示可变长的字符序列,后者存放的是某种给定类型对象的可变长序列。

2.using namespace :: name命名空间的using声明。

std::cin 的意思是要使用命名空间std中的名字cin。

头文件不应包含using声明。

标准库类型string (使用string类型必须首先包含string头文件)  string定义在命名空间中 #include<string>    using std::string

1.定义和初始化string类型  

string a;  //默认初始化为空字符串     string = "zifuchuan";  

使用=号 执行的是拷贝初始化,相反不使用则为直接初始化。如果要初始化的值有很多,则用直接初始化 string a("zifuchuan"); string a(10,'c');

2.string对象上的操作

(1)读写操作

string对象对自动忽略开头的空白(空格、换行、制表符)并从第一个真正的字符开始读起,直到遇到下一个空白。

读取未知数量的string对象:      string word; while(cin>>word);

(2)getline(is, s)  从is中读取一整行赋给s返回is

第一个参数是一个输入流cin ,第二个参数是一个string对象。getline从给定的输入流中读入内容,直到遇到换行符未知,此时换行符也被读入,然后把所读的内容存入到string对象中,此时不存换行符。getline只要一遇到换行符就结束读取操作并返回结果。如果读入的字符串中有空白格,最终也会被输出。

(3)s.empty( ) 和s.size( )  

empty是string的一个成员函数,使用点操作符就可以执行函数,如果字符串为空返回true,不为空返回false。 if(!line.empty())

size也是string的一个成员函数,用于输出string对象的长度。如果字符串被初始化时里面有空格会被记录在长度里;如果字符串默认初始化为空,后来手动输入一个字符串,且里面有空格的话,这个空格不被记录在长度里。  

s.size( ) 的返回值是一个string::size_type类型的值,他是一个无符号类型的值,返回无符号整数型unsigned,能够存下任何string对象的大小。如果一条语句已经有了size函数就不要再使用int了,可以避免int 和unsigned 同时存在可能带来的问题。

(4)比较string对象

string会逐一比较对象中的字符,同一个字母的大写和小写是不一样滴。== 和 != 为检测两个对象相等与否。还有< 、<=、 >、 >=。

如果a,b两个字符串长度不同,较短的a的每个字符都与较长的b的对象对应位置上的字符一致,则a<b

如果a,b两个字符串再某些对应的位置不一致,则比较第一对相异字符。eg:  hello < hiya    i比e大。

(5)为string对象赋值     

对于string类而言,允许把一个对象的值赋给另一个对象。  string st1="asasa" ,  st2;     st1= st2 ;     

(6)两个string对象相加,字面值和string对象相加

两个string对象相加 string s3=s1+s2;   

字面值和string对象相加,必须取保每个加法运算符的两侧至少有一个是string对象。 

string s6= s1+" hahaha "+s2;

string s7= s3+" dsdsds "+"aaaaaa";    s1+"dsdsds"的结果是一个string对象。   

3.处理string对象中的字符

两个常用的cctype头文件中的函数。cctype头文件定义的一组标准库函数能够改变某个字符的特性。

ispunct(c) 当c是标点符号时为真

toupper(c) 如果c时小写字母,则输出对应的大写字母,否则原样输出c

(1)对字符串中每个字符操作

使用范围for语句,遍历每个元素。eg:  string str="pikaqiu" ;   for (auto c : str)   cout<<c<<endl;

(2)改变字符串中的每个字符

使用范围for语句,不过循环变量要定义成引用类型。 for(auto &c : str)  cout<< c<<endl;

(3)只处理字符串中一部分字符

有两种方式:使用下标和迭代器。

下标接受的输入参数是string::size_type 类型的值,从0开始记起。

下标必须大于等于0而小于s.size(),所以s[s.size()-1]是最后一个字符。

下标的值称为索引。

在访问指定的字符以前,首先检查是否为空。

对于下标的定义: decltype( s.size() ) index=0;

标准库类型vector

vector表示对象的集合,其中所有对象的类型都相同。

要使用vector,必须包含头文件:   #include<vector>  using std::vector

vector是模板而非类型,由vector生成的类型必须包含vector中元素的类型,比如vector<int> 

1.定义和初始化

vector<T> v1  ;  V1是一个空vector,他潜在的元素是T型的,执行默认初始化;

vector<T> v2={a,b,c,.......,} ;   v2包含了初始值的元素,每个元素被赋予相应的初始值;

vector<T> v3(n,val);     v3包含了N个重复的元素,每个元素的值都是val,如果没有写val,则执行默认初始化。

最常见的方式时先定义一个空vector,然后当运行时获取到元素的值后再逐一往里面添加。

允许把一个vector对象的元素拷贝到另一个vector对象。需要注意的是两个vector对象的类型必须相同。

如果vector对象的元素是内置类型,比如int,则初始化为0;如果为string类型,则初始化为空字符串。

vector<int> v1(10,1); v1有十个值,每个值为1

vector<int> v2{10,1}; v2有两个值,101

vector<int> v3(10);   v3有十个值,执行默认初始化,每个值都是0

vector<string> v4{10}; v4有十个默认初始化的元素,都为空字符串

2.vector支持的操作

1)向vector对象中添加元素

最常见的定义方式是先定义一个空vector然后再往里添加。

添加元素应用的是vector的成员函数s.push_back(i)。此函数依次把获取到的值i添加到vector对象的尾端。

2)其他

v.empty()v.size()其操作和string类型一样。

v.size()的返回类型也是size_type类型。如果要定义的话 vector<int>::size_type

3)使用范围for语句,和string用法一样

4)对象的索引

vector使用下标运算符来获取指定的元素,下标也是从0开始,类型是size_type

如果s是一个空vector,里面不包含任何元素,那么就不能通过下标去访问。

vector对象以及string对象的下标运算符可以用于访问已经存在的元素,而不能用于添加元素。

迭代器(访问单个元素或字符,和下标运算符类似)

所有的标准库容器都可以使用迭代器,但只有少数支持下标运算,所以迭代器更为通用。

1.使用迭代器

类似于指针,迭代器提供了对对象的间接访问;和指针不同的是,获取迭代器不使用取地址符,而是用成员函数begin()end()

s.begin()负责返回指向第一个元素或字符的迭代器;s.end()负责返回指向对象尾元素的下一位置的迭代器,也就是说指向一个不存在的尾端。无意义,只是表示处理完了容器中所有的元素而已。end成员返回的迭代器通常称为尾后迭代器。

如果容器为空,则beginend返回的都是同一个迭代器,都是尾迭代器。

2.标准容器迭代器的运算符

*iter 返回迭代器iter所指元素的引用

下面代码实现了把对象的第一个字母变为大写。

string s="abcde"; if(s.begin()!=s.end()) autoit=s.begin();*it=toupper(*it);

首先要判断s是否为空;it表示s的第一个字符,使用auto类型;最后解引用变化字母。

3.移动元素

++iter   --iteriter指向容器中的下一个元素/上一个元素(移动了一个位置)

4.迭代器类型

一般来说不知道迭代器的类型,而实际上拥有迭代器的标准库类型使用iteratorconst_iterator来表示迭代器类型。

前者能读写元素,后者只能读不能写元素。

每个容器类定义了一个名为iterator的类型,该类型支持迭代器概念上所规定的一套操作。

beginend返回的具体类型由对象是否为常量决定。如果对象是常量,则返回const_iterator,否则返回iterator类型。

为了便于得到const_iterator类型的返回值,C++11引入了两个新函数cbegincend。无论vectorstring本身是否为常量,返回值都是const_iterator

5.结合解引用和成员访问操作

箭头运算符把解引用和成员访问两个操作结合起来,it->empty()等同于(*it).empty()

依次输入s的每一行直至遇到第一个空白为止:

for(auto it=s.cbegin();it!=s.cend() &&it->empty();++it) cout<<*it<<endl;

因为循环从头至尾只是读取s的元素而未向其中写值,所以用cbegincend来控制。

6.迭代器运算

vectorstring迭代器支持的运算

1iter+n  iter-n

令迭代器和一个整数值相加或相减,其返回值是向前或向后移动了若干个位置的迭代器。

2iter1 -iter2(无加法运算)

只要两个迭代器指向的是同一个容器中的元素或尾元素的下一位置,就可以相减,其结果是两个迭代器的距离。

所谓距离是右侧迭代器向前移动多少位置就能追上左侧迭代器,类型名为difference_type的带符号整型数,所以这个距离可正可负。

3)关系运算符 >>=<<=

数组

类似于vector。相同点是数组也是存放类型相同的对象的容器;不同点是,数组的大小确定不变,不能随意向数组中添加元素。

如果不清楚元素的确切个数,还是用vector。

1.定义和初始化

unsigned a=12; constexpr unsigned b=12;

string c[a]; 错误    string d[b]; 正确                   维度必须为一个常量表达式

显示初始化:

int a[ ] ={0,1,2,3};                 如果声明没有指定维度,编译器会根据初始值的数量计算并推导出来

int b[ 5 ] ={0,1,2 };               如果维度比提供的初始值数量大,则用提供的初始值初始化靠前的元素,剩下的元素被初始化成默认值(0或者空字符串)

值得注意的是:用字符串字面值去初始化数组时,字符串结尾的空字符也会占一个空间。所以存储字符串“abc” 需要的数组是a[4] 而非a[3];

不能将数组的内容拷贝给其他数组作为初始值,也不能用数组为其他数组赋值。

数组本身就是对象,所以运行定义数组的指针和数组的引用。 

数组的指针:int  (*parray)[10]=&arr;   parray是一个指针,它指向int型数组,数组中包含10个元素。

数组的引用:int (&parray)[10]=  arr;    parray是一个引用,它应用的对象是一个大小为10的数组,数组中元素的类型是int。

想要理解数组声明的含义,可以按照由内而外的顺序阅读。

2.访问数组元素

在使用数组下标的时候,通常定义成size_t类型,无符号类型,被设计的足够大能表示内存中任意对象的大小。在cstddef头文件中定义了这种类型。

数组下标的定义:constexpr size_t sz=5;

数组除了大小固定以外,其他用法都与vector基本类似。需要遍历所有元素时可以用for语句。注意防止下标越界。

3.指针和数组

数组的元素也是对象,对数组的元素使用取地址符就能得到指向该元素的指针。string *p = &nums[0] ;p指向nums的第一个元素。

在很多用到数组名字的地方,编译器都会自动将其替换为指向数组首元素的指针: string *p=nums; 等价于 p=&nums[0];

在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。数组的操作实际上是指针的操作。

指针也是迭代器。vector和string的迭代器支持的运算,数组全部支持。

4.标准库函数begin()和end()

这两个函数与容器的两个成员功能类似,不过数组不是类类型,所以这两个函数不是成员函数,正确的形式是将数组作为它们的参数。

int ia[ ] = {0,1,2,3,4,5,6};   int *beg=begin(ia);  指向ia首元素的指针  int *last=end(ia);指向ia尾元素的下一位置的指针。这两个文件定义在iterator头文件中。

特别注意尾后指针不能执行解引用和递增操作。

5.指针运算

给一个指针加上或减去某整数值,结果仍是指针。新指针比原指针前进或后退了某整数个位置。

两个指针相减的结果是带符号型的名为ptrdiff_t的类型。定义在头文件cstddef中。

只要两个指针指向同一个数组的元素,或者指向该数组的尾元素的下一位置,就能使用关系运算符进行比较。

6.解引用和指针

int ia[ ] = {0,1,2,3,4};   int last=*(ia+4); 表达式*(ia+4)计算ia前进4个元素后的新地址,解引用该结果的指针的效果类似于ia[4]。
如果写成 int last = *ia +4 ; 则表示last=ia[0] +4 =0+4=4

7.下标和指针

内置的下标运算符所用的索引值不是无符号类型的,可以为负值,这一点与string和vectror不同。

8.C风格字符串的函数

strcmp(p1,p2);比较p1 p2的相等,相等返回0 ,P1>P2返回一个正值,P1<P2返回一个负值。      

strcat(p1,p2);  将P2附加到P1之后,返回P1。

strcpy(p1,p2);  将P2拷贝给P1。返回P1。

9.多维数组

C++所说的多维数组其实是数组的数组。

使用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型。

0 0
原创粉丝点击