C++ Primer
问题
- p68 头文件
- p166 练习5.14
- 左值 右值
- 顶层const,底层const
Chapter 2 变量和基本类型
基本内置类型
- 明知数值不可能为负时,选用无符号类型
- 若数值超过了int型,选用long long
- 执行浮点运算选用double
变量
- 声明
变量可以被声明多次,但只可被定义一次
extern int i; //声明i而非定义i
int j;//声明并定义j
extern double pi = 3.1415;//定义
- 当你第一次使用变量时再定义它
- 全局变量可能会被内层作用域覆盖
复合类型
引用(默认为左值引用)
引用即为对象起了另外一个名字,且必须初始化,初始值必须是一个对象
引用本身不是对象,所以不能定义引用的引用
int ival = 1024;
int &refVal = ival;//refVal指向ival(是ival的另一个名字)
指针[从右往左看变量]
- 指针本身就是一个对象
因为引用不是对象,没有实际地址,所以不能定义指向引用的指针 - 空指针生成方法
int *p1 = nullptr;
int *p2 = 0;
int *p3 = NULL;
指针必须初始化
int ival = 42;
int *p = &ival;
- 指向指针的引用
int i = 42;
int *p; //p为int型指针
int *&r = p;//r是一个对指针p的引用c++
r = &i;
*r = 0;
const限定符
- 共享const对象,在前添加extern
- const的引用
const int ci = 1024;
const int &r1 = ci;
初始化常量引用时,允许用任意表达式作为初始值,尤其,允许为一个常量引用绑定非常量的对象、字面值,甚至是一个一般表达式,允许用字面值初始化常量引用
int i = 42;
const int &r1 = i; //允许将const int& 绑定到一个普通int对象上
const int &r2 = 42; //正确,常量引用 但是,int &r2 = 42 是错误的,初始化需是一个对象
const int &r3 = r1 * 2;//正确,常量引用
int &r4 = r1 * 2;//错误,r4是一个普通的非常量引用
- 指向常量的指针
想要存放常量对象的地址,只能使用指向常量的指针
const double pi = 3.14;
const double *cptr = π
- 常量指针(必须初始化)
int errNumb = 0;
int *const curErr = &errNumb; //curErr将一直指向errNumb
- 顶层const
顶层const表示指针本身是个常量 (也就是int *const ptr;)
底层const表示指针所指的对象是个常量(相当于const int *ptr)
- constexpr
声明为一个constexpr类型,以便由编译器来验证变量的之是否是一个常量表达式
处理类型
- typedef/using,类型别名
typedef double wages;//wages是double的同义词
using SI = Sales_item;//SI是Sale_item的同义词
- auto类型说明符
【预留】 - decltype类型指示符
const int ci = 0; &cj = ci;
decltype(ci) x = 0; //x的类型是const int
decltype(cj) y = x; //y的类型是const int&,有绑定到变量x
decltpye ((variable))的结果永远是引用,而decltpe (variable)的结果只有当variable本身就是一个引用才是引用
自定义数据结构
- 类所在的头文件的名字应与类的名字一样。
- 预处理器,头文件保护符
#ifdef
#define
#endif
Chapter3 字符串、向量和数组
命名空间的using声明
using namespace::name;
using std::cin;
using std::cout;
using std::endl;
标准库类型string
#include<string>
using std::string
- 直接初始化和拷贝初始化
string s1
string s2(s1)
string s2 = s1
string s3("value")
string s4(n,'c') //把s4初始化为由连续n个字符c组成的串
其中使用“=”为拷贝初始化,不使用等号则为直接初始化。
- “cin>>”运算符读取到空格为止
- “getline”直到遇到换行符为止
- string.size()返回的是无符号整型数,其数据类型为size_type
- string相加时,要确保每个加法运算都有一个运算对象是string
string s4 = s1 + ", "; //正确,一个string对象和一个字面值相加
string s7 = "hello" + ", " + s2;//错误,不能把字面值直接相加
字符串字面值与string是不同的类型
- C++版本的C标准库头文件
name.h 或者cname 字母c表示这是一个属于C语言标准的头文件,特别的,在名为cname的头文件中定义的名字从属于命名空间std。 - 处理字符串的每个字符【for】
string str("some string");
for (auto c : str)//每行输出str中的一个字符
cout << c << endl;
- 使用for语句改变字符串中的字符
想要改变string对象中字符的值,必须把循环变量定义成引用类型
string s("Hello World!!!")
for (auto &c : s)//此处c为引用类型
c = toupper(c);//转换成大写形式
cout << s << endl;
标准库类型vector
相当于一个动态的数组
#inlucde<vector>
using std::vector
- 初始化vector对象
vector<T> v1//空vector对象
vector<T> v2(v1)//等价于vector<T> v2 = v1
vector<T> v3(n,val)
vector<T> v4{a,b,c...}//等价于vector<T> v4 = {a,b,c...}
vector<T> v5(n)//会创建一个值初始化的元素初值,例如int型自动设置为0.
使用数组初始化vector对象
int int_arr[] = {0, 1, 2, 3, 4, 5}
vector<int> ivec(begin(int_arr), end(int_arr));
- 向vector对象中添加元素
先创建一个空的vector,运行时再利用vector的成员函数push_back向其中添加元素
string word;
vector<string> text; //空vector对象
while (cin >> word){
text.push_back(word);
}
vector对象的下标运算符可用于访问已存在的元素,而不能用于添加元素。且只能对已知存在的元素执行下标操作。
- 同样可以使用【范围for】来访问或者修改vector对象,与string类似,且修改vector对象时访问变量必须为引用类型(&)
迭代器介绍
迭代器的对象是容器中的元素或者string对象中的字符
vector<int>::iterator it;
string::iterator it2;
string s("some string");
if (s.begin() != s.end()){ //确保s非空
auto it = s.begin(); //it表示s的第一个字符
*it = toupper(*it); //将当前字符改成大写形式
}
- (*it).empty() 等价于 it->empty()
//依次输出text的每一行直至遇到第一个空白行为止
for (auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it)
cout << *it << endl;
- 凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素
- 不能在范围for循环中向vector对象添加元素
迭代器运算
iter + n
iter - n
iter1 += n
iter1 -= n
iter1 - iter2 //只要两个迭代器指向的是同一个容器中的元素或者尾元素的下一位置,就能将其相减
- 使用迭代器运算
//二分搜索
auto beg = text.begin(), end = text.end;
auto mid = text.begin() + (end - beg)/2;//初始状态下的中间点
while (mid != end && *mid != sought){
if(sought < *mid)
end = mid;
else
beg = mid + 1;
mid = beg + (end - beg)/2;
}
数组
- 维度必须是常量表达式(constexpr)
- 引用不是对象,不存在引用的数组
int *ptrs[10]; //ptrs是含有10个整型指针的数组
int (*Parray)[10] = &arr; //Parry指向一个含有10个整数的数组
- string不是c内置数据类型,因此类似于”string sa[10];”这样的定义语句,sa数组中为空。
- 数组下标常用size_t类型
- begin(array),end(array),区别于迭代器中的v1.begin(),v1.end();
指针和数组
- 尾后指针不能执行解引用和递增操作
多维数组
- 使用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型,防止数组被自动转成指针(auto)
- 多维数组遍历
1.范围for
int ia[3][4];
for (auto p = ia; p != ia + 3; ++p) {
for (auto q = *p; q != *p + 4; ++q)
cout << *q << ' ';
cout << endl;
}
2.标准函数库begin,end
for (auto p = begin(ia); p != end(ia); ++p{
for (auto q = begin(*p); q != end(*p); ++q)
cout << *q << ' ';
cout << endl;
}
Chapter4 表达式
算数运算符
- ( -m ) / n 和 m / ( -n )都等于 - ( m / n )
- m % ( -n ) 等于m % n
- ( -m ) % n 等于 - ( m % n )
- 算数 > 关系 > 逻辑
i != j < k;// 等价于 i != ( j < k );
赋值运算符
- 因为赋值运算符的优先级低于关系运算符的优先级,所以在条件语句中,赋值部分通常应该加上括号
int i;
while ((i = get_value()) != 42){ //赋值运算加括号
.....
}
位运算符
【预留】
sizeof运算符
【预留】
类型转换
【预留】
Chapter6 函数
参数传递
- 当函数无需修改引用形参的值时最好使用常量引用
bool isShorter(const string &s1, const string &s2){
return s1.size() < s2.size();
}
- main:处理命令行选项
int main(int argc, char **argv){}
int main(int argc, char *argv[]) {}
- initializer_list 形参
函数的实参数量未知但是全部实参的类型都相同,可以使用initializer_list类型的形参
【预留】
返回数组指针
- 类型别名
typedef int arrT[10];//arrT是一个类型别名,它表示的类型是含有10个整数的数组
using arrT = int[10];//arrT的等价声明
arrT* func(int i);//func返回一个指向含有10个整数的数组的指针
- 声明一个返回数组指针的函数
int (*func(int i))[10]
// func(int i)表示调用func函数时需要一个int类型的实参
// (*func(int i))意味着我们可以对函数调用的结果执行解引用操作
// (*func(int i))[10]表示解引用func的调用将得到一个大小是10的数组
// int (*func(int i))[10]表示数组中的元素是int类型
- 使用尾置返回类型
函数真正的返回类型跟在形参列表之后
auto func(int i) -> int (*)[10];
//func接受一个int类型的实参,返回一个指针,该指针指向含有10个整数的数组
函数重载
同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载函数。
- 不允许两个函数除了返回类型外其他所有的要素都相同
Record lookup(const Account&);
bool lookup(const Account&);//错误:与上一个函数相比只有返回类型不同
- 重载和const形参
拥有顶层const的形参会被忽略
Record lookup(Phone);
Record lookup(const Phone);//重复声明
Record lookup(Phone*);
Record lookup(Phone* const);//重复声明
如果形参是某种类型的指针或引用,则可以区分,此时的const是底层的
Record lookup(Account&); //函数作用于Account的引用
Record lookup(const Account&); //新函数,作用于常量引用
Record lookup(Account*); //新函数,作用于指向Account的指针
Record lookup(const Account*); //新函数,作用于指向常量的指针
- 在不同的作用域中无法重载函数名
特殊用途语言特性
【预留】