c++定义了内容丰富的抽象数据类型库,其中,string和vector是两种最重要的标准库,string支持可变字符串,vector支持可变长合集;
内置数组是一种更基础的类型,string和vector都是对它的某种抽象;
字符串向量和数组
命名空间using声明
我们大部分使用的库函数都属于命名空间std中,而程序也显式的将这一点标识出来。
有using声明就无需专门的前缀也可以使用所需的名字。
#include <iostream>
using std::cin;
int _tmain(int argc, _TCHAR* argv[])
{
int i;
cin >> i;
//cout << i; //错误,没有对应的using声明,必须使用完整的名字;
std::cout << i;
return 0;
}
按照规定,每个using声明引入命名空间中的一个成员
标准库类型string
标准库类型string标识可变长的字符序列,使用string必须包含string头文件。作为标准库的一部分,string定义在命名空间std中;
定义和初始化
如何初始化类型的对象是由类本身决定的。一个类可以定义多个初始化对象的方式,只不过这些方式之间有所区别;
int _tmain(int argc, _TCHAR* argv[])
{
string s1; //默认初始化,s1是空字符串
string s2 = s1; //s2是s1的副本
string s3 = "sYstemk1t"; //s3的值等于sYstemk1t
string s4(10, 'c'); //s4的内容是10个c
return 0;
}
直接初始化和拷贝初始化
如果使用等号初始化一个变量,实际上执行的是拷贝初始化,编译器把等号右侧的值拷贝到新创建的对象中去。反之,如果不适用等号,则执行的是直接初始化;
string s5 = "sYstemk1t"; //拷贝初始化
string s6("sYstemk1t"); //直接初始化
string s7(5, 's');
string对象操作
一个类除了要规定初始化其对象的方式外,还要定义对象上所能执行的操作;
读写string
使用IO操作符来读写string对象:
#include <iostream>
#include <string>
using std::string; using std::cin; using std::cout; using std::endl;
int _tmain(int argc, _TCHAR* argv[])
{
string s;
cin >> s;
cout << s << endl;
return 0;
}
getline读取整行
有时我们希望能在最终得到的字符串中保留输入时的空白符,这时应该用getline代替>>运算符。
#include <iostream>
#include <string>
using std::string; using std::cin; using std::cout; using std::endl;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string line;
while (getline(cin,line))
{
cout << line << endl;
}
return 0;
}
empty和size
empty函数根据string对象是否为空返回一个对应的布尔值;
empty
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string line;
while (getline(cin,line))
{
if (!line.empty())
{
cout << line << endl;
}
}
return 0;
}
size
size函数返回string对象的长度;
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string line;
while (getline(cin,line))
{
cout << line << line.size() << endl;
}
return 0;
}
size_type类型
对于size函数来说,size函数返回的是一个size_type类型的值;
比较string对象
string类定义了几种用于比较字符串的运算符。这些比较运算符逐一比较string对象中的字符,并且对大小写敏感;
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string s1 = "Hello";
string s2 = "hello";
string s3 = "hello World";
if (s1 != s2)
{
cout << "s1 == s2" << endl;
}
if (s3 > s2)
{
cout << "s3 > s2" << endl;
}
return 0;
}
string相加
对象相加
两个string对象相加得到一个新的string对象,其内容是把左侧的运算对象与右侧的对象串接而成;
#include <string>
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string s1 = "Hello", s2 = "world";
string s3 = s1 + s2;
cout << s3 << endl;
s1 += s2;
cout << s1 << endl;
return 0;
}
字面值和string对象相加
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string s1 = "Hello", s2 = "world";
string s3 = s1 + "sYstemk1t" + s2 + '\n';
cout << s3 << endl;
return 0;
}
处理string对象中的字符
如果我们需要处理string对象中的字符,处理这些情况常常要设计语言和库的很多方面;
for
c11中提供了新标准的一种语句:范围for语句;这种语句便利给定序列中的每个元素并对序列中的每个值执行某种操作,其语法是:
#include <ctype.h>
int _tmain(int argc, _TCHAR* argv[])
{
string s("Hello,,!~!@@#!World");
decltype(s.size()) punct_cnt = 0; //decltype用于推断数据类型
for (auto c : s) //对于s中的每个字符
{
if (ispunct(c)) //如果该字符是标点符号
{
++punct_cnt;
}
}
cout << punct_cnt << endl;
return 0;
}
for改变字符串的字符
如果需要改变string对象中字符的值,必须把循环变量定义成引用类型;
#include <ctype.h>
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string s("Hello,World");
for (auto &c : s) //对于s中的每个字符,c是一个引用变量
{
c = toupper(c);
}
cout << s << endl;
return 0;
}
处理部分字符
想要访问string对象中每个字符有两种方法:一种是下标,另一种是迭代器;
下标
#include <ctype.h>
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string s("Hello,World");
if (!s.empty())
{
s[3] = toupper(s[3]);
}
cout << s << endl;
return 0;
}
下标迭代
int _tmain(int argc, _TCHAR* argv[])
{
string s("Hello World");
decltype(s.size()) index = 0;
for (; index != s.size() && !isspace(s[index]); ++index)
{
s[index] = toupper(s[index]);
}
cout << s << endl;
return 0;
}
标准库类型vector
标准库类型vector表示对象的集合,其中所有对象的类型都相同。集合中的每个对象都有一个与之对应的索引,索引用于访问对象;
C++有类模板,也有函数模板,其中vector是一个类模板。
定义和初始化vector对象
和任何一种类类型一样,vector模板控制着定义和初始化向量的方法。
可以默认初始化vector对象,从而创建一个指定类型的空vector;
列表初始化vector对象
c++11新标准还提供了另外一种为vector对象的元素赋初值的方法,即列表初始化。
vector<string> articles = {
"a","an","the"};
创建指定数量的元素
还可以用vector对象容纳的元素数量和所有元素的统一初始值来初始化vector对象;
vector<int> ivec(10,-1); //10个int类型的元素,每个初始化为-1
vector<string> svec(10,"HI"); //10个string类型的元素
值初始化
通常情况下,可以只提供vector对象容纳的元素数量而不用略去初始值。此时库会创建一个初始化元素初值,并把它赋给容器中的所有元素。
如果vector对象的元素是内置类型,则元素初始值为0;
vector<int> ivec(10); //10个元素,每个初始化为0
vector<string> svec(10); //10个元素,每个都是空string对象
列表初始值
在某些情况下,初始化的真实含义依赖于传递初始值时用的是花括号还是圆括号。
vector<int> v1{
10}; //v1有10个元素,每个值都是0
vector<int> v2(10); //v2有1个元素,该元素的值是10
vector<int> v3(10,1); //v3有10个元素,每个值都是1
vector<int> v4{
10,1}; //v4有2个元素,值分别是10和1
vector<string> v5{
"HI" }; //列表初始化,v5有一个元素
vector<string> v6("HI"); //错误初始化
vector<string> v7(10); //v7有10个默认初始化的元素
vector<string> v8{
10, "HI" }; //v8有10个值为hi的元素
向vector对象中添加元素
int _tmain(int argc, _TCHAR* argv[])
{
string s1;
vector<string> text;
while (cin >> s1)
{
text.push_back(s1);
for (size_t i = 0; i < text.size(); i++)
{
cout << text[i] << endl;
}
}
其他vector操作
除了push_back意外,vector还提供了其他操作,大部分都和string的相关操作类似;
vector的empty和size两个成员与string的同名成员功能一致;empty检查vector对象是否包含元素然后返回一个布尔值;size则返回vector对象中元素个数;