《C++ Primer》第三章 字符串、向量和数组

《C++ Primer》第三章 字符串、向量和数组

3.1 命名空间的using声明

using namespace::name;

3.2 标准库类型 string

string: 表示可变长的字符序列, 头文件必须包含#include。

标准库string的输入运算符自动忽略字符串开头的空白(包括空格符、换行符、制表符等等),从第一个真正的字符开始读起,直到遇见下一处空白为止。

getline则从给定的输入流中读取数据,直到遇到换行符位置,此时换行符也被读取进来,但是并不存储在最后的字符串中。

初始化string对象方式

  • string s1:默认初始化s1为一个空串。
  • string s2(s1):直接初始化,s2是s1的副本。
  • string s2=s1::拷贝初始化,等价于s2(s1)。
  • string s3(“value”):直接初始化,s3是"value"的副本。
  • string s3=“value”:拷贝初始化,等价于s3(“value”)。
  • string s4(n,‘c’):直接初始化,把s4初始化为由连续n个字符c组成的串。

string操作

  • os<<s:将s写到输出流os当中,返回os

  • is>>s:从is读字符串赋给s,字符串以空白分隔,返回is

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

  • s1+s2: 返回s1和s2连接后的结果,要确保+两侧的运算对象至少有一个是string。字面值字符串与string是不同的类型!!!

  • s[n]:返回s中第n个字符的引用,位置n从0开始计算

  • s.empty():s为空返回true,否则返回false

  • s.size():返回s中字符的个数

  • s1 = s2:用s2的副本代替s1中原来的字符

  • s1==s2: 如果s1和s2中所含字符完全一样,则相等

  • <,<=,>,>=:按字典序比较

比较示例:

string str = "Hello";
string phrase = "Hello World";
string slang = "Hiya";

按字典序比较: str<phrase;slang>str; slang>phrase

cctype头文件中的函数

  • isalnum©:当c是字母或数字时为真。
  • isalpha©:当c是字母时为真。
  • iscntrl©: 当c是控制字符时为真。
  • isdigit©:当c是数字时为真。
  • isgraph©:当c不是空格但可打印时为真。
  • islower©:当c为小写字母时为真。
  • isprint©:当c是可打印字符时为真(即c是空格或c是可视形式)。
  • ispunct©:当c是标点符号时为真。
  • isspace©:当c是空白时为真。
  • isupper©:当c是大写字母时为真。
  • isxdigit©:当c是十六进制数字时为真。
  • tolower©: 转换为小写字母。
  • toupper©:转换为大写字母。

基于范围的for语句:

for (declaration: expression)
statement

declaration中加上&代表会改变其中的值

string s("Hello World!!!");
for (auto &c : s)   		//对于s中的每个字符(c是引用)
    c = toupper(c);			//c是一个引用,因此赋值语句将改变s中字符的值
cout << s << endl;

3.3 标准库类型 vector

vector: 存放的是某种给定类型对象的可变长序列.

定义和初始化vector对象:

  • vector v1 v1是一个空vector,潜在的元素是类型的,执行默认初始化
  • vector v2(v1) v2中包含v1所有元素的副本
  • vector v2=v1 等价于v2(v1)
  • vector v3(n,val) v3包含了n个重复的元素,每个元素值都是val
  • vector v4(n) v4包含了n个重复地执行了值初始化的对象, 如果是int类型,则默认初始化为0
  • vector v5{a,b,c…} v5包含了初始值个数的元素,每个元素被赋予相应的初始值
  • vector v5={a,b,c…} 等价于v5{a,b,c…}

使用push_back()添加元素

其余vector操作:

  • v.empty() 如果v不含有任何元素,返回真;否则返回假
  • v.size() 返回v中元素的个数
  • v.push_back(t) 向v的末尾添加一个值为t的元素
  • v[n] 返回v中第n个位置上元素的引用
  • v1 = v2 用v2中元素的拷贝替换v1中的元素
  • v1 = {a,b,c…} 用列表中元素的拷贝替换v1中的元素
  • v1==v2 当其元素相同时返回true
  • <,<=,>,>= 按字典序比较

注意:通过下标访问不存在的元素的行为会导致缓冲区溢出(buffer overflow)。

3.4 迭代器介绍

迭代器:

  • 迭代器本身
  • 容器定义的迭代器类型
  • 某个迭代器对象
auto b = v.begin(), e = v.end();
//b表示v的第一个元素,e表示v尾元素的下一位置
vector<int>::iterator it; //it能读写vector<int>的元素
string::iterator it2;	//it2能读写string对象中的字符
vector<int>::const_iterator it3; //it3只能读元素,不能写元素
string::const_iterator it4;	//it4只能读字符,不能写字符

begin和end返回的具体类型由对象是否是常量决定,如果是常量,则返回const_iterator;如果不是常量,返回iterator。为了便于得到const_iterator类型的返回值,C++11新标准引入了两个新函数,分别是cbegin和cend。

vector<int> v;
const vector<int> cv;
auto it1 = v.begin();	//it1的类型是vector<int>::iterator
auto it2 = cv.begin();  //it2的类型是vector<int>::const_iterator
auto it3 = v.cbegin();	//it3的类型是vector<int>::const_iterator

标准容器迭代器的运算符:

  • *iter :返回迭代器iter所指元素的引用
  • iter->mem:解引用iter并获取该元素的名为mem的成员吗,等价于(*iter).mem
  • ++iter:令iter指示容器中的下一个元素
  • –iter:令iter指示容器中的上一个元素
  • iter1 == iter2 判断两个容器是否相等
  • iter1!=iter2:同上

将string对象中第一个单词改为大写模式:

//依次处理s的字符直到处理完全部字符或者遇到空白
for (auto it = s.begin();it != s.end() && !isspace(*it); ++it)
	*it = toupper(*it);

//依次输出text的每一行直至遇到的第一个空白行为止
for (auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it)
    cout << *it << endl;

​ vector和string迭代器支持的运算

  • iter + n:新位置与原来相比向前移动了n个元素
  • iter - n:新位置与原来相比向后移动了n个元素
  • iter1 += n:将iter1加n的结果赋给iter1
  • iter1 -= n:将iter1减n的结果赋给iter1
  • iter1 - iter2: 将运算符右侧的迭代器向前移动差值个元素后得到左侧的迭代器
  • <,<=,>,>= 迭代器的关系运算符,如果某迭代器指向的容器位置在另一个迭代器所指位置之前,则说前者小于后者。

使用迭代器完成二分搜索:

auto beg = text.begin(), end = text.end();
auto mid = text.begin() + (end-beg)/2;
//当还有元素尚未检查并且我们还没有找到sought时执行循环
while (mid != end && *mid != sought){
	if(sought < *mid)
		end = mid;
	else
		beg = mid + 1;
	mid = beg +(end - beg)/2;
}

3.5 数组

定义数组时必须指定数组的类型,不允许用auto关键字由初始值的列表推断类型。和vector一样,数组的元素应为对象,因此不存在引用的数组。

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

int a[]={0,1,2};
int a2[]=a;    //错误,不能用一个数组初始化另一个数组
a2 = a;		//不能把一个数组直接赋给另一个数组

int *ptrs[10];	//ptrs是含有10个整型指针的数组
int &refs[10]=/* ? */ //错误,不存在引用的数组
int (*Parray)[10] = &arr;	//Parray指向一个含有10个整数的数组
int (&arrRef)[10] = arr;	//arrRef引用一个含有10个整数的数组
int *(&array)[10] = ptrs;   //arry是数组的引用,该数组有10个指针

指针和数组:对数组使用取地址符就能得到指向该元素的指针

指针本身的值是一个内存地址值,表示指针所指对象在内存中的存储地址;指针所指的对象可以通过解引用指针访问;因为指针也是一个对象,所以指针也存储在内存的某个位置,它有自己的地址。

string nums[]={"one","two","three"};
string *p = &nums[0];       //p指向nums的第一个元素
string *p2 = nums;			//等价于p2 = &nums[0]

int ia[] = {0,1,2,3,4,5,6,7,8,9};
auto ia2(ia);				//ia2是一个整型指针,指向ia的第一个元素
ia2 = 42					//错误:ia2是一个指针,不能用int值给指针赋值
//编译器执行过程
auto ia2(&ia[0]);            //ia2的类型是int*
//ia3是一个含有10个整数的数组
decltype(ia)  ia3 = {0,1,2,3,4,5,6,7,8,9};
ia3 = p;		//错误:不能用整型指针给数组赋值
ia3[4] = i;		//正确:把i的值赋给ia3的一个元素

C++ 11 新标准引入了两个名为begin和end的函数,示例如下:

int ia[]={0,1,2,3,4,5,6,7,8,9};
int *beg = begin(ia);		//指向ia首元素的指针
int *last = end(ia);		//指向arr尾元素的下一位置的指针

c风格字符串的函数: 头文件#include

strlen(p)		//返回p的长度,空字符不见算在内
strcmp(p1,p2)	//p1==p2,返回0;p1>p2,返回一个正值;否则返回一个负值
strcat(p1,p2)	//将p2附加到p1之后
strcpy(p1,p2)	//p2拷贝给p1,返回p1

c_str()函数的返回值是一个C风格的字符串,函数的返回结果是一个指针,该指针指向一个以空字符结束的字符数组,而这个数组所存的数据恰好和那个string对象的一样。结果指针的类型是const char*,从而确保不会改变字符数组的内容。

char *str = s;	//错误,不能用string对象初始化char*
const char *str = s.c_str();	//正确

使用数组初始化vector元素

int arr[]={0,1,2,3,4,5};
vector<int> ivec(begin(arr),end(arr));
vector<int> vec(arr+1,arr+4);	//拷贝三个元素

3.6多维数组

初始化:

int  a[3][4]={
	{0,1,2,3},
	{4,5,6,7},
	{8,9,10,11}
};
int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
//显示初始化每行元素
int a[3][4]={{0},{4},{8}};

size_t cnt=0;
for	(auto &row: a)			//对于外层数组的每一个元素
	for (auto &col:row){	//对于内层数组的每一个元素
		col = cnt;			///将下一个值赋给该元素
		++cnt;
	}

int ia[3][4];
int (*p)[4] = ia;	//p指向含有4个整数的数组
p = &ia[2];			//p指向ia的尾元素

int *ip[4];			//整型指针的数组
int (*ip)[4];		//指向含有4个整数的数组

//p指向ia的第一个数组
for(auto p = begin(ia);p!=end(ia); ++p){
    // q指向内层数组的首元素
    for(autro q=begin(*p);q!=end(*p);++q)
        cout<<*q<<‘ ’;
    cout<<endl;
}

using int_array = int[4];
typedef int int_array[4];

for(int_array *p=ia;p!=ia+3;++p){
    for(int *q=*p;q!=*p+4;++q)
        cout<<*q<<' ';
   cout<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1100dp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值