《C++ Primer》笔记(02)
覆盖内容
第 2 章 变量和基本类型
笔记
算术类型
- 使用
signed和unsigned区分是否带符号,char类型在不同的机器上的默认符号区分是不同的 - 明确数值非负时使用
unsigned - 使用
int进行整数运算,越界则使用long long - 算术表达式中不要使用
char和bool,理由为不同机器上的不同表现 - 浮点运算使用
double,float常常精度不够
默认类型转换(简)
非bool=>bool:非0为true,0为falsebool=>非bool:true为1,false为0float=>int:仅保留整数部分int=>float:小数部分记0unsigned赋越界值:初始值对总值取模后的余数,如将-1赋值给unsigned char(0~255),结果值为-1对256取模后的余数255;如果在i递减的for循环中使用unsigned类型且循环条件为i>=0,则该循环为死循环,因为unsigned类型无负值,始终满足循环条件signed赋越界值:undefined- 应避免在表达式中混用多种类型计算
- 隐式类型转换优先级参考链接和C++11的规定
字面值常量
- 默认十进制,
0开头八进制,0x开头十六进制 - 负号不在字面值内
- 末尾加
e0代表科学计数法【* 10^0】 - 浮点数默认字面值类型为
double - 单个字符
'A'为char型字面值,"hello"为字符串字面值,是字符构成的数组,尾部有空字符\0(实际长度为长度+1,length()函数返回值不计空字符) - 转义序列被认作为一个字符
\考虑后三位数字,\x考虑后续所有数字- 指定字面值类型参考规定
变量
- C++11 单个变量也可以采用
int i{51};的列表初始化方式来进行初始化,可以检查信息丢失 - 默认值,
string为空串,其他类型如在函数体外(全局作用域下)则为0,否则为不确定值(或未定义)
声明与定义
- 使用
extern来声明变量 - 声明与定义的区别在于是否进行申请空间和初始化
- 变量可被声明多次,但只能定义一次,如果变量跨文件使用则只在一个文件中定义,其他使用位置声明
引用和指针
- 引用即别名,不会申请新空间,只能被绑定到一个已经初始化的对象上(不能是常量),引用不能被引用
- 指针是一个对象,可以指向新的对象,无须赋初值,存放指向对象的地址
- 使用
int *p = nullptr;来定义空指针,不能把int变量直接赋值给指针,即使变量值为0;在条件中为false void类型的指针可以存放任意类型对象的地址,但无法直接操作所指对象- 练习 2.23 参考链接
- 声明符包括了类型修饰符(
*、&、const等)和变量名,而非数据类型包括类型修饰符,int*p1, p2;将会定义指针p1和整型变量p2 - 使用
*的个数区分指针的级别,复杂的指针和引用的定义采用右结合方式解读,如int *p; int *&r = p;``p为指向int类型的指针,r为引用(&r),引用的对象为指针(*),指针指向的类型为整型(int),初始化值为p
const限定符
- 默认下常量仅在文件内有效
- 使用
extern让多个文件共用定义的常量 - 可以引用常量,不可修改常量,只有常量引用/指针可以引用/指向常量,普通的非常量引用/指针不行
- 如果常量引用
r1引用的是非常量i,则不可通过r1来改变i,可以通过其他方法改变i const double *p1 = &i;允许指向常量的指针p1改变指向对象,不允许改变对象的值(对象为常量)double *const p2 = &j;不允许常量指针p2改变指向对象(p2本身就是常量),但可以通过p2改变指向对象的值(对象为double类型,不是常量)- 顶层:是否可改变指向的对象;底层:是否可改变指向对象的值
constexpr限定符
- 使用
constexpr修饰的变量必定是常量或其值是由该修饰词修饰的函数的返回值 - 修饰的指针不能是野指针
- 函数体内定义的变量不能用
constexpr修饰
处理类型
类型别名
- C++11
using S = Sdudent;声明别名 typedef char *pstring; const pstring cstr = 0;pstring是char *的别名,即指向char类型的指针类型(作为基本数据类型),cstr是一个const pstring类型的常量(const修饰pstring而非char),即指向该类型的常量指针(顶层)
auto类型说明符
auto定义必须有初值- 由于一条声明语句只能有一个基本数据类型,所以一条
auto声明中变量的初始类型要相同 - 如果右值为引用,
auto将会忽略掉引用,将类型指定为所引用的类型 auto会忽略顶层const,保留底层const;如果需要保留顶层const可以使用const auto f = ci;指定,将引用的类型设为auto时使用默认的初始化规则
decltype类型指示符
decltype会保留顶层const和引用- 有
int i = 42, &r = i;,则decltype(r)返回int &,decltype(r + 0)返回int,decltype(i = 0)返回int &(赋值运算符返回左值的引用) decltype(variable)返回变量本身的类型,decltype((variable))则总返回引用(变量为可以作为左值的特殊表达式,加上括号将变为引用)
auto和decltype的区别
int i = 42, * p = &i, & r = i;
decltype(i) x1 = 0; //因为 i 为 int ,所以 x1 为int
auto x2 = i; //因为 i 为 int ,所以 x2 为int
decltype(r) y1 = i; //因为 r 为 int& ,所以 y1 为int&
auto y2 = r; //因为 r 为 int& ,但auto会忽略引用,所以 y2 为int
decltype(r + 0) z1 = 0; //因为 r + 0 为 int ,所以 z1 为int,
auto z2 = r + 0; //因为 r + 0 为 int ,所以 z2 为int,
decltype(*p) h1 = i; //h1 是int&,*解引用操作返回引用
auto h2 = *p; // h2 为 int.
自定义数据结构
头文件保护
- 在头文件中,使用
#ifdef、#ifndef、#define和#endif来避免头文件的重复引用,#ifdef和#ifndef用于判断变量是否已经被#define,并执行直到#endif为止的操作。 - 也可将
#pragma once放在头文件首,该方法兼容性并不完全(部分老编译器无法识别),但效率比上一种方法高
练习代码
#include <iostream>
#include <string>
/* 2.10
std::string gStr;
int gInt;
*/
int main()
{
/* 2.3
unsigned u1 = 10, u2 = 42;
int i = 10;
std::cout << u2 - u1 << std::endl;
std::cout << u1 - u2 << std::endl;
std::cout << i - u1 << std::endl;
std::cout << u1 - i << std::endl;
*/
/*
std::cout << u8"hi" << std::endl;
*/
/* 2.7
int month = 09;
*/
/* 2.8
std::cout << "2\115\n";
std::cout << "2\115\12";
std::cout << "2\t\115\n";
*/
/* 2.9
std::cin >> int val;// Wrong, syntax error
int i = { 3.14 }; // Wrong, data lost
double salary = wage = 99.99; // Wrong, syntax error
int j = 3.14;// Right, data lost
*/
/* 2.10
std::string lStr;
int lInt;
std::cout << gStr << ";" << gInt << ";" << lStr << ";" << lInt << std::endl;// empty;0;empty;undefined
*/
/* 2.12
int _;
_ = 1;
std::cout << _ << std::endl;
int catch-22;
int 1_or_2 = 1;
*/
/* 2.14
int i = 100, sum = 0;
for (int i = 0; i != 10; ++i) {
sum += i;
}
std::cout << i << ";" << sum << std::endl;
*/
/*
std::string str1;
std::string str2 = "";
std::cout << str1.length() << std::endl;
std::cout << str2.length() << std::endl;
str2 = "\0";
std::cout << str2.length() << std::endl;
str2 = "a\0";
std::cout << str2.length() << std::endl;
*/
/* 2.16-2.17
int i = 0, & r1 = i;
double d = 0, & r2 = d;
r2 = 3.14;
r2 = r1;
i = r2;
r1 = d;
std::cout << r2 << ";" << i << ";" << r1 << std::endl;
i = 5;
r1 = 10;
std::cout << i << ";" << r1 << std::endl;
*/
/*
int i = 20;
int* p1 = &i;
int** p2 = &p1;// p2是一个指向【指向int类型指针】的指针
int* p3 = p1;// p3是一个指向int类型(int *)的指针,其值等于p1(同样是指向int类型的指针)
std::cout << "i=" << i << "\np1=" << p1 << "\n*p1=" << *p1 << "\n&i=" << &i << "\np2=" << p2 << "\n*p2=" << *p2 << "\n**p2=" << **p2 << "\n&p1=" << &p1 << "\n&p2=" << &p2 << std::endl;
std::cout << "p3=" << p3 << "\n*p3=" << *p3 << std::endl;
int*& r1 = p1;// r1是一个【指向int类型的指针】的引用,即p1的别名
int j = 10;
r1 = &j;// 令p1指向j
std::cout << "p1=" << p1 << "\n*p1=" << *p1 << std::endl;
std::cout << "r1=" << r1 << "\n*r1=" << *r1 << std::endl;
*r1 = 0;// 解引用r1得j,赋值j=0
std::cout << j << std::endl;
*/
/* 2.30-2.31
int i = 1;
const int v2 = 0;
int v1 = v2;
int* p1 = &v1, & r1 = v1;
const int* p2 = &v2, * const p3 = &i, & r2 = v2;
std::cout << "i=" << i << "\nv2=" << v2 << "\nv1=" << v1 << "\n*p1=" << *p1 << "\nr1=" << r1 << "\n*p2=" << *p2 << "\n*p3=" << *p3 << "\nr2=" << r2 << "\n\n";
r1 = v2;
// p1 = p2;// 非常量指针不能指向常量
// p1 = p3;
p2 = p1;
p2 = p3;
*/
/* 2.33-2.35
int i = 0, & r = i;
auto a = r;
const int ci = i, & cr = ci;
auto b = ci;
auto c = cr;
auto d = &i;
auto e = &ci;
const auto f = ci;
auto& g = ci;
// auto& h = 42;
const auto& j = 42;
auto k = ci, & l = i;
auto& m = ci, * p = &ci;
// auto& n = i, * p2 = &ci;
std::cout << "a = " << a << "\nb = " << b << "\nc = " << c << "\nd = " << d << "\ne = " << e << "\ng = " << g << std::endl;
std::cout << "-----------------------------------------------------------" << std::endl;
a = 42; b = 42; c = 42;
// d = 42; e = 42; g = 42;
std::cout << "a = " << a << "\nb = " << b << "\nc = " << c << "\nd = " << d << "\ne = " << e << "\ng = " << g << std::endl;
const int i = 42;
auto j = i;
const auto& k = i;
auto* p = &i;
const auto j2 = i, & k2 = i;
// i = 0; // const int
j = 0; // int
// k = 0; // const int & const
// *p = 0;
p = &j; // const int *
std::cout << "*p = " << *p << std::endl;
// j2 = 0; const int
// k2 = 0; // const int & const
*/
/* 2.36
int a = 3, b = 4;
decltype(a) c = a;
decltype((b)) d = a;
++c;
++d;
std::cout << "a = " << a << "\nb = " << b << "\nc = " << c << "\nd = " << d << std::endl;
*/
/* 2.38
int i = 42, * p = &i, & r = i;
decltype(i) x1 = 0; //因为 i 为 int ,所以 x1 为int
auto x2 = i; //因为 i 为 int ,所以 x2 为int
decltype(r) y1 = i; //因为 r 为 int& ,所以 y1 为int&
auto y2 = r; //因为 r 为 int& ,但auto会忽略引用,所以 y2 为int
decltype(r + 0) z1 = 0; //因为 r + 0 为 int ,所以 z1 为int,
auto z2 = r + 0; //因为 r + 0 为 int ,所以 z2 为int,
decltype(*p) h1 = i; //h1 是int&,*解引用操作返回引用
auto h2 = *p; // h2 为 int.
*/
return 0;
}
浙公网安备 33010602011771号