C++ Primer 第三章
2021.4.29
3.1命名空间的using声明
using namespace::name;
- 头文件不应包含using声明
3.2 标准库类型string
string定义在命名空间std中
-
初始化
using std::string; string s1; //空字符串 string s3="haha"; //s3是字面值的副本 string s4(5,'a'); //s4内容为aaaaa
-
string对象的操作
s1+s2
返回s1与s2连接后的结果<, <=, >, >=
按字符的字典序比较,对大小写敏感string.getline()
读取一行的内容string.empty()
返回字符串是否为空bool值string.size()
返回字符串大小,返回类型为string::size_type
- 读取文件中所有字符串
int main() { string word; while(cin>>word) //输入运算符返回流参数 cout<<word<<endl; return 0; }
-
getline
读取一整行的内容,至换行符为止。注意若输入流中为\naaa\n,则会得到一个空string
返回流参数
-
string::size_type
大致为一个无符号整型数,应避免将
string.size()
得到的结果与有符号数进行混用 -
字面值与string对象相加时必须确保每个加法运算符两侧的运算对象至少有一个是
string
string s2=s1+","; //正确 string s3="hello"+","; //错误,两个运算对象都不是string string s4="hello"+","+s1; //错误 string s5="hello"+(","+s1); //正确
2021.5.4
3.2.3 处理string对象中的字符
-
cctype
头文件中的函数//返回bool值 isalnum(c); //c为字母或数字时为真 isalpha(c); //c为字母时为真 isdigit(c); //是否为数字 isxdigit(c); //是否为十六进制数字 iscntrl(c); //是否为控制字符 isspace(c); //是否为空白 isgraph(c); //c不是空格但可打印时为真 isprint(c); //c是可打印字符时为真(空格或具有可视形式) ispunct(c); //c是标点符号时为真(不是控制字符/数字/字母/可打印空白) islower(c); //是否为小写字母 isupper(c); //是否为大写字母 //返回字符 tolower(c); //若c为大写字母,则输出小写字母,否则原样输出 toupper(c); //若c为小写字母,则输出大写字母,否则原样输出
-
建议使用C++版本的c标准库头文件
eg. 使用
cname
而非name.h
,使用cctype
而非ctype.h
-
C++11标准的for语句
#include <cctype> #include <iostream> using std::cout; using std::string; using std::endl; int main(void) { string s("h##el lo~!!\n!"); decltype(s.size()) punct_cnt = 0; decltype(s.size()) space_cnt = 0; for (auto &c : s) { if (ispunct(c)) ++punct_cnt; if (isspace(c)) ++space_cnt; c=toupper(c); } cout << punct_cnt << "\t" << space_cnt << endl; cout << s; return 0; }
运行结果:
6 3
H##EL LO~!!
!
2021.5.5
3.3 标准库类型vector
vector
表示对象的集合,常被称作容器
若想使用vector,则需:
#include <vector>
using std::vector;
- 因为引用不是对象,故不存在包含引用的
vector
- 使用花括号/圆括号区分初始化的含义
vector<int> v1(10,1); //10个元素,每个元素值都为1
vector<int> v2{10,1}; //2个元素,分别为10,1
- 若使用花括号,初始化过程会尽可能把花括号内的值当作元素初始值的列表来处理,只有无法执行列表初始化时才会考虑其他初始化方式
vector<string> v3{"hi~"}; //1个元素
//vector<string> v4("hi~"); //错误
vector<string> v5{10}; //无法进行列表初始化,故进行默认值初始化,
//v5包含10个默认初始化的元素
2021.5.6
在定义vector时没有必要设定其大小
若循环体内有向vector对象添加元素的语句,则不能使用范围for循环(范围for语句体内不应改变其所遍历的序列的大小)
-
vector操作
v.push_back(v1)
添加对象v.empty()
检测v是否为空v.size()
返回v元素个数v[n]
v中第n个元素的引用 -
只有当元素的值可比较时,vector对象才能被比较
-
vector与string的下标运算符只可用于访问已存在的元素,而不能用于添加元素
2021.5.10
3.4 迭代器
所有标准库容器都可以使用迭代器,string也可以使用迭代器
3.4.1 使用迭代器
auto b=v.begin(), e=v.end();
//b表示v的第一个元素,e表示v尾元素的下一位置
迭代器运算符:
*iter; //返回迭代器所指元素的引用
++iter; //令iter指示容器中的下一个元素
–iter; //令iter指示容器中的上一个元素
iter1==iter2 //判断两个迭代器是否相等,是否指示的是同一个元素/是同一个容器的尾后迭代器
- 不可以对
end()
返回的迭代器使用++
运算符 - 迭代器数据类型:
iterator
和const_iterator
begin()
与end()
的返回类型默认为iterator
,若想指定为const_iterator
,需使用cbegin()
与cend()
- 在for循环中改变容器的容量,会导致iterator失效,所有使用的迭代器的循环体,都不要向迭代器所属的容器添加元素
2021.5.12
3.4.2 迭代器运算
string与vector的迭代器提供了更多额外的运算符:
iter+n
iter-n
结果为比原位置移动n个元素的位置
iter1-iter2
结果为它们之间的距离,可证可负,结果类型名为difference_type
>
>
=
<
<=
若某迭代器指向的容器位置在另一迭代器所指位置之前,则前者小于后者
2021.5.13
3.5 数组
数组大小确定不变,不可随意增加元素。若不清楚元素的确切个数应使用vector
数组的声明中数组纬度应为常量表达式constexpr
,不允许用auto
关键字推断类型
默认情况下数组元素被默认初始化。
- 字符串字面值结尾处有一个空字符,在使用字符串字面值初始化字符数组时应注意纬度
- 不允许拷贝和赋值
int *ptrs[10]; //ptrs是含有10个整形指针的数组
//int &refs[10]; //错误:不存在引用的数组
int (*Parray)[10]=&arr; //Parray指向一个含有10个整数的数组
int (&arrRef)[10]=arr; //arrRef引用一个含有10个整数的数组
int *(&arry)[10]=ptrs; //arry是一个含有10个整形指针的数组的引用
当需要遍历数组的所有元素时,最好的办法也是使用for语句
2021.6.5
数组下标类型通常为size_t
,size_t
在cstddef
头文件中被定义
3.5.3 指针和数组
int a[]={0,1,2,3,4,5,6,7,8,9}; //a是一个含有10个整数的数组
auto b(a); //此时b的类型为一个整形指针
decltype(a)c={2,3,4,5,6,7,8,9,0}; //此时c的类型为含有10个整数的数组
-
标准库函数begin和end
int a[]={1,2,3}; int *beg=begin(a); int *last=end(a); //指向arr尾元素的下一位置的指针,不可解引用 auto n=last-beg; //a数组中元素的个数两个指
-
两个指针指向同一数组是可以用关系运算符进行比较;指向不相关的对象时则不能比较他们
-
内置的下标运算符所用的索引值不是无符号类型
2021.7.13
3.5.4 C风格字符串
- 在C++中应尽量避免使用,易出现bug&漏洞
3.5.5 与旧代码的接口
-
混用string对象和C风格字符串
-
允许使用以空字符结束的字符数组来初始化string对象或为string对象赋值
-
在string对象加法中允许使用以空字符结束的字符数组作为其中1个运算对象
-
在string对象的复合赋值运算中允许使用以空字符结束的字符数组作为右侧的运算对象
-
string s; const char *str=s.c_str();//可得到一个c风格字符串(不可保证得到的str不变)
-
若运行以下程序:
int main() { string s("hello"); const char *str=s.c_str(); printf("%s\n",str); s.erase(s.begin()); //str变化 s.append("s"); //str变化 s+="9"; //str不变化 printf("%s\n",str); }
结果为
hello ellos
-
-
使用数组初始化vector对象
int int_arr[]={0,1,2,3,4,5}; vector<int> vect1(begin(int_arr),end(int_arr));//vect1与int_arr内容相同 vector<int> vect2(int_arr+1,int_arr+4);//vect2中为{1,2,3}
3.6 多维数组
for(const auto &row:a) //&引用号不可省略,否则回自动转为int*
for(auto col:row)
{...}
- 程序使用多维数组的名字时也会自动将其转换成指向数组首元素的指针