文章目录
c++primer学习心得-第三章-字符串、向量和数组
3.1 命名空间的using声明
形式为: using namespace::name ;
如
using std::cout;using std::cin;using std::endl;
需要注意的是头文件中不应该有using 声明。
3.2 标准库类型string
string 表示可变长的序列,使用string必须首先包含string头文件。
#include<string>;using std::string;
1. 初始化string
- string s1;
- string s2(s1);
- string s2=s1;
- string s3(“value”);
- string s3=“value”;
- string s4(n,‘c’);
2. string对象上的操作
- os<<s 将s写到输出流中,返回os
- is>>s 从is中读取字符串赋给s,字符串以空白分隔,返回is
- getline(is,s) 从is中读取一行赋值给s,返回is
- s.empty() s为空返回ture否则返回false
- s.size() 返回s中字符串个数
- s[n] 返回s中第n个字符串的引用,从0计数
- s1+s2 返回s1和s2连接后的结果
- s1=s2 用s2的副本代替s1原来的字符串
- s1==s2 s1和s2完全一样返回true
- s1!=s2 判断是否相等,对大小敏感
- <,<=,>,>= 利用字符在字典中的顺序进行比较,对大小敏感
#include<iostream>
#include<string>
using namespace std;
int main() {
string s1,s;
cin >> s1;
cout << s1 << endl;
getline(cin, s);
cout << s << endl;
if (getline(cin,s)) {
if(s.empty()){
cout << "s is empty" << endl;
}
else {
cout << "the size of s is : " << s.size() << endl;
for (int i = 0; i < s.size(); s, i++) {
cout << "s[" << i << "]= " << s[i] << endl;
}
}}
cout << s1 + s << endl;
if (s1 == s) {
cout << "s1=s" << endl;
}
else {
s1 = s;
}
cout << s1 << "===" << s << endl;
return 0;
}
3.处理string对象中的字符
在cctype头文件中定义了以下一组标准库函数:
- isalnum(c)—>c是字母会数字时为真
- isalpha(c)—>c是字母时为真
- ischtrl(c)—>c是控制字符时为真
- isdigit(c)—>c是数字时为真
- isgraph(c)—>c不是空格但可以打印时为真
- islower(c)—>c是小写时为真
- isprint(c)—>c是可打印字符时为真(可以时空格)
- ispunct(c)—>c是标点符号时为真(不是控制字符、数字、字母、可打印空白)
- isspace(c)—>c是空白时为真(c是空格、横向制表符、纵向制表符、回车符、换行符、进纸符中的一种)
- isupper(c)—>c是大写字母时为真
- isxdigit(c)—>c是十六进制数字时为真
- tolower(c)—>如果c是大写输出对应的小写字母,否则原样输出c
- toupper(c)—>如果c是小写输出对应的大写否则原样输出
利用for语句遍历给定序列的每个元素:
for(declaration:expression)
statement
如
string str("some string");
for(auto c:str)
cout<<c<<endl;
如下面代码定义了一个统计一段字符串中的各种字符类型的出现次数
#include<iostream>
#include<string>
using namespace std;
void readstr(string str) {
if (!str.empty()) {
int alpha = 0, cntrl = 0, digit = 0, graph = 0, lower = 0, upper = 0, print = 0, punct = 0, space = 0;
//字母,控制字符,数字,不是空格可打印,小写字母,大写字母,可打印,标点符号,空白
for (auto c : str) {
if(isprint(c)){
print++;
if(isgraph){
graph++;
if (isalpha(c)) {
alpha++;
if (islower(c))
lower++;
else
upper++;
}
if (isdigit(c))
digit++;
if (ispunct(c))
punct++;
}
}
if (isspace(c))
space++;
}
cout << "字母:"<< alpha<< ",控制字符:" <<cntrl<< " ,数字:" <<digit<< ",不是空格可打印:" <<graph
<< ",小写字母:" <<lower<< ",大写字母:"<<upper << ",可打印:" <<print<< ",标点符号:" <<punct<< ",空白:"<<space << endl;
}
}
int main() {
string s1("aaaaAAA1231234sdfgw3sa,sd,d,d,f,,f,s ...asa..\n\t\d\s\a\\\S\ASD\DAFXCVZ\PSFSF;;D`` sddfasfxvf");
readstr(s1);
//s1 = "aaa";
for (auto &str : s1) {
str=toupper(str);
}
cout << s1 << endl;
return 0;
}
结果为
字母:53,控制字符:0 ,数字:8,不是空格可打印:81,小写字母:33,大写字母:20,可打印:81,标点符号:17,空白:7
AAAAAAA1231234SDFGW3SA,SD,D,D,F,,F,S ...ASA..
DS\SASDDAFXCVZPSFSF;;D`` SDDFASFXVF
3.3 标准库类型vector
vector表示对象的集合,其中的所有对象的类型都相同。使用vector必须包含对应的头文件。vector是一个类模块。模板本身不是类或函数,相反可以将模板作为编译器生成类或函数的一份说明。编译器根据模板生成类或函数的过程称为实例化(instantiantion)。使用模板时应指出编译器应把类或函数实例化为何种类型。
对于vector,需要给定vector内存放的对象的类型,如
vector<int> ivec;
vector<Sales_item> sales;
vector<vector<string>>file;
vector能容纳大多数类型的对象作为其元素。
1. 定义和初始话vector
- vector v1
- vectorv2(v1)
- vector v2=v1
- vectorv3(n,val)
- vectorv4(n) n个重复执行初始化的对象
- vector v5{a,b,c,…} 列表初始化,注意是花括号不是圆括号
- vector v5={a,b,c,…}
2.向vector中添加元素
利用vector的成员函数push_back,把一个值push到vector对象的尾端。
vector<int> vi;
for(int i=0;i!=100;i++)
vi.push_back(i);
3. 其他vector操作
- v.empty()
- v.size()
- v.push_back(t)
- v[n]
- v1=v2
- v1={a,b,c,…}
- v1==v2
- v1!=v2
- <,<=,>,>=
4.迭代器(iterator)
1.使用迭代器
除了使用下标运算符来访问string对象的字符或vector对象的元素,还可以使用迭代器。
迭代器的类型拥有begin和end成员,begin成员负责返回指向第一个元素的迭代器。end成员负责返回指向容器“尾元素的下一个位置(one past the end)”的迭代器。
迭代器运算符:
- *iter 返回迭代器iter所指元素的引用
- iter->mem 解引用iter并获取该元素的名为men的成员,等价于(*iter).men
- ++iter iter指向容器的下一个元素
- –iter 指向容器的上一个元素
- iter1==iter2
- iter1!=iter2
如下我们对比用指针和用迭代器来遍历string和vector,相比较可以看出二者虽然方式不同但其实是很相似的,但迭代器用起来更方便一些。
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main() {
string s{ "asdfasdf" };
vector<int> a{ 1,2,3,2,231,2,2,1,3 };
for (char* p = &s[0]; p!=&s[s.size()-1]; p++) {
cout << *p << endl;
}
for (int* pi = &a[0]; pi != &a[a.size() - 1]; pi++) {
cout << *pi << endl;
}
for (auto str = s.begin(); str != s.end(); str++) {
cout << *str << endl;
}
for (auto cc = a.begin(); cc != a.end(); cc++) {
cout << *cc << endl;
}
return 0;
}
(注意迭代器大多数没有定义<运算符,但基本都定义了==和!=运算符,所以我们要养成用!=的习惯。
迭代器类型
一般来说我们不需要知道迭代器的类型是什么,实际上标准库类型使用iterator和const_iterator来表示迭代器的类型。
vector<int>::iterator it;
string::iterator its;
vector<int>::const_iterator cit;
string::const_iterator cits;
const_iterator和常量指针差不多。
注意解引用和访问成员操作时:
(*it).empty();//必须要加括号
为了简化操作,我们这时可以用箭头运算符(->)
it->empty();
2.迭代器运算
- iter+n
- iter-n
- iter+=n
- iter-=n
- iter1-iter2
- > >= < <=
5. 数组
数组与vector非常像,但数组的大小时不可变得,也就不能随意的向数组添加元素。
1. 定义和初始化内置数组
unsigned cnt=42;
constexpr unsigned sz=42;
int arr[10];
int *parr[sz];
string bad[cnt];//错误,cnt不是常量表达式
string strs[get_size()];//get_size是constexpr时正确,否则错误
const unsigned ssz=3;
int ia1[ssz]={0,1,2};
int a2[]={0,1,2};
int a3[5]={0,1,2}; //<=>int a3[]={0,1,2,0,0};
sring a4[3]={"hi","bye"};
int a5[2]={0,1,2}; //错误
//字符数组的特殊性
char a1[]={'c','+','+'}; //列表初始化,无空字符
char a2[]={'c','+','+','\0'}; //显示添加空字符
char a3[]="c++"; //自动添加表示字符串结束的空字符
consr char a4[6]="Daniel"; //错误,没有空间存放空字符
//不允许拷贝和赋值
int a[]={0,1,2};
int b[]=a; //错误
b=a; //错误
//复杂的声明
int *ptrs[10]; //ptrs是一个具有10个整型指针的数组
int (*parray)[10]=&arr;//parray指向一个含10个整数的数组
int (&arrRef)[10]=arr;//arrRef引用一个含有10
int *(&arrr(10))=ptrs; //arrr是一个含有10个指针的引用
注意不存在引用的数组。
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main() {
int a[10];
int(*pa)[10] = &a;
int(&af)[10] = a;
for (int i = 0; i != size(a); i++) {
//(*pa)[i] = i;
af[i] = i;
}
for (auto c : a)
cout << c << endl;
return 0;
}
2. 访问数组元素
使用数组下标时通常将其定义为size_t类型。size_t是一种与机器无关的无符号类型。在cstddef中定义了size_t类型,这个文件是c标准库stddef.h头文件的c++版本。
3.指针和数组
数组有一个特性:在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首个元素的指针
string nums[]={"one","two","three"};
string *p=&nums[0];
string *p1=nums;
int ia[]={0,1,2,3,4,5,5,6,7,8,9};
auto ia2(ia);//ia2是一个指向ia第一个元素的指针,等价于 auto ia2(&ia[0]), 类型为 int *
decltype(ia)ia3={0,1,2,3,4,5,6,7,8,9};
但decltype(ia)返回的类型是10个整数的数组。
数组也能使用迭代器,相关的操作也都支持,但用法有所不同。
int ia[]={0,1,2,3,4,5,5,6,7,8,9};
int *beg=begin(ia);
int *last=end(ia);
auto n=begin(ia)-end(ia);
两个指针相减的结果的类型是一种名为ptrdiff_t的标准库类型,是带符号的。
4. c风格字符串
c风格字符串是一种约定俗成的写法。c语言标准库提供一组函数来操作c分隔字符串,他们定义在cstring头文件中,cstring是c语言头文件string.h的c++版本。
- strlen(p) 返回p的长度,不计算空字符
- strcmp(p1,p2) 相等时返回0,p1>p2时返回一个正值,p1<p2返回一个负值
- strcat(p1,p2) p2附加到p1之后,返回p1
- strcpy(p1,p2) p2拷贝给p1,返回p1
6.多维数组
严格地说c++中没有多维数组,通常所谓的多维数组时数组的数组。
for语句来处理多维数组
for(const auto &row:ia)
for(auto col:row){
cout<<col<<endl;
}
用指针遍历二维数组时可能有点绕,一定要理清楚一些概念(指针指向的是数组还是数组中的元素)
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main() {
int a[10][10];
int o = 0;
for (int(*p)[size(a)] = a; p != a+size(a); p++)
for (int* pp = *p; pp != *p+size(*p); pp++)
*pp = o++;
for (const auto& c : a)
for (auto cc : c)
cout << cc << endl;
return 0;
}
或者可以用auto来进行简写,但最好明白不用auto怎么写,要理解到位
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main() {
int a[10][10];
int o = 0;
for (auto p=a;p!=a+size(a); p++)
for (auto pp=*p;pp!=*p+size(*p); pp++)
*pp = o++;
for (const auto& c : a)
for (auto cc : c)
cout << cc << endl;
return 0;
}