(三)字符串、向量和数组

命名空间using声明

声明后无需前缀就能使用对应名字,对每个名字都需要进行独立的using声明。头文件不应包含using声明,防止与调用文件产生名字冲突。

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

int main() {
	cout << "输入两个值" << endl;
	int v1, v2;
	cin >> v1 >> v2;
	cout << "sum:" << v1 + v2 << endl;
	return 0;
}

标准库类型string

1.头文件及声明

#include<string>
using std::string;

2.定义及初始化string对象

	string s1;//默认为空
//拷贝初始化,有等号
	string s2 = "123";
	string s3 = s2;
//直接初始化
	string s4(10,'c');
//使用string或字符串数组构造初始化
	string str1 = "hhdyzwhy";
	string str2(str1,4,4);  //输出zwhy,(string变量,第几个开始,拷贝几个)
	//可使用string或者const char*对象进行初始化
	string str3(cp,n); //cp是字符串数组,第一项为指针,第二项为个数,str3是从cp开始的n个字符的拷贝
	string str4(s2,pos2);//s2为string类型,从下标开始拷贝至空字符结束
	//eg:空字符为'\0'
	const char* cp = "hhdyzwhy!";  //必须以空字符结尾
		string s = "hhdyzwhy!";
		string s1(cp,4); //hhdy
		string s6(cp + 1, 4); //hdyz
		string s2(s, 4); //从下标4开始
		string s3(cp, 2, 1);//d
		cout << s1 << '\n' << s6<<'\n'<<s2 << '\n' << s3 << endl;
		//char cs[] = {'a','b','\0'};
		char cs[] = "abc"; //必须以空字符结尾
		string s4(cs);//abc
		string s5(cs, 1);//a
		cout << s4 << '\n' << s5 << endl;
//使用substr拷贝初始化
		string s7 = s.substr(0, 4); //hhdy
		string s8 = s.substr(4);//zwhy!
		cout << s7 << '\n' << s8 << endl;
//使用替换函数进行赋值
		s.assign(4,'h');//hhhh
		s.assign(s7.begin(),s7.begin()+1);//h

3.string修改操作

  • 顺序容器常规操作
  • insert和erase除迭代器外接受下标位置定位,insert支持插入C风格字符数组以及字符串
c.append(str); //字符串末尾插入
c.replace(pos,n,str);//将下标位置处开始的n个字符串替换为str

4.string搜索操作

  • 6个搜索函数,4个重载版本
  • 成功返回string::size_type值,失败返回string::npos静态成员
  • 注意,last相关查找是从后往前,pos位置写的是起始位置,如果找0到10内是否有字符串,pos = 10。
	string s = "yhhdyzwhhhhhdy!";
	string s2 = "zwhy";
	char cstr[] = "dy";
	vector<string::size_type> i(7,0);
	i[0]= s.find("hhdy");//字符串第一次出现的位置,返回1
	i[1] = s.find("zwhy");//找不到,返回npos
	i[2] = s.rfind(cstr);//dy最后一次出现位置,返回12
	i[3] = s.find_first_of("dy", 5);//dy在s[5]之后第一次出现的位置,返回12
	i[4] = s.find_last_of(cstr, 0, 1);//返回npos,因为last相关是从后往前查找,pos = 0,从0查到0
	i[5] = s.find_first_not_of("hdy");//第一次不出现“hdy”中字符的位置,返回5(z)
	i[6] = s.find_last_not_of("hdy");//最后一次不出现“hdy”中字符的位置,返回14(!)
	const char cstr1[] = "hdy";
	i[7] = s.find_last_of(cstr1,14,1); //返回11

5.string 对比函数

  • s.compare
//()内可省略
(pos1,n1),s2,(pos2,n2)//和string对比,对比pos开始n个字符
(pos1,n1),cp,(n2)//字符数组指针cp,n2个字符比较

6.数值转换

to_string(val) //val是任意算术类型
//string转换为int、long、unsignedlong、longlong、unsignedlonglong
stoi(s,p,b)//p为s下标,b为基数(默认10)。
stol(s,p,b)
stoul(s,p,b)
stoll(s,p,b)
stoull(s,p,b)
//string转换为float、double、long double
stof(s,p)
stod(s,p)
stold(s,p)

4.string对象操作

对象操作

//os,is为输入输出流,istringstream,ostringstream
os<<s 将s写入输出流os,返回os
is>>s 从is中读取字符串给s,返回is
getline(is,s) 从is中读取一行赋给s,返回is

//读写操作
cin>>s; //忽略开头的空白,输出到下一处空白为止。
getline(cin, s3) //每次获取一行,不包括换行符

//内存操作
s.empty() //是否为空
s.size() //返回字符串长度
//比较操作,按照字典序比较
>=,<=,>,<,==,!=//关系运算符和相等性运算符都可以使用

//赋值,相加
//字符串和字面值相加,两侧对象都要至少有一个string变量,不能两个字面值相加赋给字符串变量,可以写在一起变成赋值语句。
//原因是c++语言中字符串字面值不是标准库string类型。
string str1 = "hhdyzwhy",str;
str2 = str1;//hhdyzwhy
str2 +=str1;//hhdyzwhyhhdyzwhy
str2 = str2 +"!"; //hhdyzwhyhhdyzwhy!
str2 = "hhdyzwhy";

//string对象中的字符操作
for(auto c:s)//循环中,处理每个字符
s[0]~s[s.size()-1]//下标运算符,索引
decltype(s.size()) index = 0;//对于下标索引的定义

size()函数返回类型

string::size_type //在类string里定义,如string的类型实际为unsigned long long;

字符判断库 <cctype>

isalnum(c)//字母或数字
isdigit(c)//数字
islower(c)//小写字母
isupper(c)//大写字母
isalgha(c)//字母
tolower(c)//大写字母输出小写,不是大写字母输出c
toupper(c)//同上,小转大
iscntrl(c)//控制字符
isgraph(c)//不是空格但可打印
ispunct(c)//标点符号
isspace(c)//空白(空格、横向制表符、回车符、换行符)

注:C++版本的C标准库
从C的c.name->C++的cname,c代表属于C语言标准库的头文件。头文件中定义的名字属于命名空间std。

标准库vector类型

vector是对象的集合,集合中每个对象都有一个对应的索引。vector也常被称为容器。

头文件及声明

#include<vector>
using std::vector;

类模板和函数模板

模板不是类和函数,是作为编译器生成类或函数编写的说明。编译器中根据模板创建类或函数的过程称为实例化。实例化时需要指出类或函数的数据类型。
早期c++

vector<vector<int> > //最右>前加空格

vector操作

//初始化和列表初始化
vector<int> num(101);//圆括号构造对象,10个元素,值为1
vector<int> num{10,1};//花括号,列表初始化,2个元素,值为10和1
vector<string> strs{10}; //10不能作为列表初始化,这里是构造10个默认初始化元素
vector<string> strs{10,"hi"};//10个值为"hi"的元素
vector<int> num = {{1},{2},{3}};

//拷贝、赋值与添加元素,添加元素时,不能使用范围for循环
num.push_back(1); //尾部插入元素
num[n] //引用,0~num.size()-1,用于访问元素,保持下标合法的手段是合理使用for循环
v1 = v2//拷贝
v1 = {1,2,3} //拷贝替换

//内存个数
num.empty();
num.size();
//比较,按照字典序来
		

迭代器

访问对象方法

下标引用
迭代器,对于容器更通用,有些容器不支持下标访问。

注:string对象不属于容器,但支持很多容器类型的操作。

迭代器定义

提供对对象的间接访问,有效迭代器指向某个元素或者指向容器中尾元素的下一个位置,可以将迭代器理解为特殊的指针。
创建迭代器同时返回迭代器成员,包括begin成员和end成员,指向第一个元素和尾元素的下一个位置。其中,end成员又被称为尾后迭代器,表示已经处理完容器中所有元素。当容器为空时,begin和end返回同一个迭代器(尾后迭代器)。

迭代器通常有三种含义:迭代器概念本身、容器定义迭代器类型、某个迭代器对象。

迭代器类型

一般来说无需精确直到迭代器类型,可以使用auto进行初始化。实际迭代器类型表示:

vector<int>::iterator it; //可以读写
vector<int>::const_iterator it;//只能读不能写 

每个容器定义一个名为“iterator”的类型,并支持迭代器相应操作。

begin和end

除了begin和end,还有cbegin和cend返回const_iterator 类型。

vector<int> v;
const vector<int> cv;
auto it1 = v.begin(); //vector<int>::iterator
auto it2 = cv.begin();//vector<int>::const_iterator
auto it3 = v.cbegin();//vector<int>::const_iterator
auto it4 = v.cend(); //vector<int>::const_iterator

迭代器解引用

*iter //解引用,此时iter必须确实指示某个元素,例end()不能引用
iter->mem //解引用iter,返回其中的mem成员

解引用获取迭代器指向的对象,如果说对象的类型是类,可以进一步访问他的成员。

(*it).empty();   //圆括号必须有
it->empty();
it->mem  //和下一行意思一样
(*it).mem

限制

当容器容量变化时,迭代器会失效。

迭代器操作

++iter //指示容器中下一个元素,例end()不能递增
--iter //指示容器中上一个元素
iter + n;
iter - n;
iter += n;
iter -= n;
iter1 - iter2 //二者之间的距离,类型的difference_type,由于距离可负可正,所以是带符号整数
//一个简单调用
	for (auto i = str.begin();i != str.end(); ++i) {
		if(islower(*i)){
			*i = toupper(*i);		
		}
		cout << *i;
	}
	cout << endl;	

数组

存放固定数量的对象,与vector相比,数组大小固定

定义和初始化

初始化大小必须是一个常量表达式,不允许使用auto指定数组类型。
不允许使用数组给数组拷贝和数组赋值,有一些编译器可能支持数组赋值,这是所谓的编译器扩展,是非标准特性;

constexpr unsigned sz = 42;
int arr[10];
int *parr[sz]; //含有42个整形指针的数组
int a3[5] = {0,1,2};

复杂数组声明

复杂数组的阅读是从内向外阅读。

int arr[10];
int (*parr)[10] = arr;
int (&refarr)[10] = arr;
int *(&arry)[10] = refarr;

数组访问

下标访问

0~arr.size(),类型size_t,cstddef头文件中定义size_t类型。

指针访问

  • 数组与指针:数组使用时编译器会把它转换成指针,数组的操作实际上是指针的操作。可以对对象使用取地址符获得指向该对象的指针。直接使用数组名字,编译器会将它编译为一个指向数组首元素的指针。
  • 通过首尾指针实现数组遍历:数组的指针可以实现和迭代器一样的功能。实现遍历时,需要知道数组首地址,和尾的后一个地址。首地址直接是数组名,尾后地址可以通过数组size数获得。或者可以使用iterator头文件中的begin()和end()函数。这两个函数不是成员函数,将数组作为他们的参数。
  • 指针运算:1.给一个指针加减某整数值,仍为指针。2.指针相减是二者之间的距离,类型是ptrdiff_t的标准库(cstddef)带符号类型3.比较。
  • 对于空指针同样可以使用以上指针运算,空指针可以加减0,两个空指针可以彼此相减,值为0。
  • 解引用和指针运算交互
	string nums[] = {"one", "two", "three", "four"};
	//数组与指针
	string *p1 = &nums[2]; //指向"three"的地址
	string *p2 = nums; //相当于&nums[0]
	auto p3(nums); //是一个string类型指针
	decltype(nums) strnum = {"a", "b", "c"}; //返回nums类型
	cout << *p2 << endl;   //"one"
	cout << *strnum << endl; //"a"

	//通过首尾指针实现数组遍历
	string beg = nums;
	string last = &nums[4];
	#include<iterator>
	string *beg1 = begin(nums);
	string *last1 = end(nums);
	
	//指针运算
	++p2; //&nums[1],"two"
	string *p4 = nums+2; //指向"three"
	auto n = p4 - p2;//值为1
	
	//解引用和指针运算交互
	int narr[] ={1,2,3,6} ;
	int last = *(narr+3); //6
	int n4 = *narr+3;// 4

指针与下标关系

  • 对于下标操作,相当于先将数组转化为指向数组首地址的指针,然后通过下标值进行指针移位。
  • 标准库类型(string、vector)下标是无符号类型(必须大于0)。内置(数组)的下标运算没这个要求。
int n[] = {0,1,2,3,4,5,6,7,8};
int i1 = ia[2];
//相当于下方的两个操作
int *p = ia;
int i2 = *(p+2);

int *p = &ia[2]; //2
int j = p[1]; //3
int k = p[-2];//0

C风格字符串(char型数组)

字符串存放在字符数组中,以空字符结束(‘\0’)。

头文件

#include<cstring>

C风格字符串操作

  • 相当于char型数组,C风格字符串名返回首个char字符地址。
  • 比较时不能使用>/<等比较符,要使用strcmp函数。
  • 也不能向string一样进行加减拼接操作。
//初始化
	char p1[] = {'C', '+', '+', '\0'};
	char p2[] = {'h', 'h', 'd', 'y', 'z', 'w', 'h', 'y', '\0'};

	cout << strlen(p1) << endl; //不算p在内的长度
	cout << strcmp(p1, p2) << endl; //比较,相等返回0,大于返回正值,小于返回负值
	cout << strcat(p1, p2) << endl; //p2附加到p1之后,返回p1,返回"C++hhdyzwhy"
	cout << p1 << endl; //返回"C++hhdyzwhy"
	strcpy(p1, p2); //p2拷贝给p1
	cout << p1 << endl; //"hhdyzwhy"

与旧代码接口

string和C风格字符串

  • C风格字符串->string
char p2[] = {'h', 'h', 'd', 'y', 'z', 'w', 'h', 'y', '\0'};
string s = p2;
string s1 = s+p2;
s1 = s+p2;
  • string->C风格字符串
const char *pstr = s.c_str(); //返回常量char型指针

vector和数组

  • 数组->vector
int n[] = {0,1,2,3,4,5,6,7,8};
vector<int> num(begin(n),end(n));
vector<int> num1(n,n+4);  //左闭右开

多维数组

c++中的数组可以理解为数组的数组。

int ia[3][4]; //大小为3的数组,每个元素是含有4个整数的数组,第一个维度是行,第二个维度是列
int arr[10][20][30] = {0}; //arr是一个大小为10的数组,数组里每个元素是大小为20的数组,数组里每个元素为30个int类型整数。

多维数组初始化

int ia[3][4] = {{1,3,2,3},{2,3,4,5},{3,4,5,6}};
int ia[3][4] = {1,3,2,3,2,3,4,5,3,4,5,6};
int ia[3][4] = {{0},{4},{8}};
int ia[3][4] = {1,3,2,3};

多维数组访问

下标引用

int ia[3][4] = {{1,3,2,3},{2,3,4,5},{3,4,5,6}};
int ia[0] //数组
int ia[0][1]//数组内元素
int (&row)[4] = ia[0] //row是ia第一行的引用

当时for循环处理数组时,除了最内层循环外,其他所有循环的控制变量都应该是引用类型,防止数组被自动转换为指针。

int ia[3][4] = {{1,3,2,3},{2,3,4,5},{3,4,5,6}};
for(const auto &row:ia)
	for(auto col:row)
	 cout<<col<<endl;

指针和多维数组

  • 使用多维数组名字时,会将其自动转换为数组首元素的指针(首元素可以是数组)。
  • 定义时p的圆括号必不可少
  • 可以使用类型别名简化指针
int ia[3][4] = {{1,3,2,3},{2,3,4,5},{3,4,5,6}};
int (*p)[4] = ia; //指向ia[0]的地址,相当于&ia[0]
++p; //指向ia[1]的地址,相当于&ia[1]
int* pp = *p; //指向p的首地址
cout << *pp << endl; //pp的值,1
//为防止数组前加指针类型,使用auto
for(auto p = ia;p!=ia+3;++p){
	for(auto q = *p;q!=*p+4;++q)
		cout<<*q<<' ';
	cout<<endl;
}
//另一种写法
for(auto p = begin(ia);p!=end(ia);++p){
	for(auto q = begin(*p);p!=end(*p);++q)
		cout<<*q<<' ';
	cout<<endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值