《C++ Primer》笔记 第2章 变量和基本类型
如果你的数值超过了int表示范围,选用long long
如果你需要使用一个不大的整数,那么明确指定它的类型是signed char或者unsigned char
执行浮点数运算选用double
当一个算术表达式中既有无符号数又有int值时,那个int值就会转换成无符号数。
当从无符号数中减去一个值时,不管这个值是不是无符号数,我们都必须确保结果不能是一个负值。
分行书写的字符串字面值
std::cout << "a really, really long string literal "
"that spans two lines" << std::endl;
如果反斜线\后面跟着的八进制数字超过3个,只有前3个数字与\构成转义序列。
字符和字符串字面值
前缀 含义 类型 u Unicode 16字符 char16_t U Unicode 32字符 char32_t L 宽字符 wchar_t u8 UTF-8(仅用于字符串字面常量) char 整型字面值
后缀 最小匹配类型 u or U unsigned l or L long ll or LL long long 浮点型字面值
后缀 类型 f or F float l or L long double 我们在使用对象这个词时,并不严格区分是类还是内置类型,也不区分是否命名或是否只读。
初始化和赋值是两个完全不同的操作。
初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而已一个新值来替代。
列表初始化:
int unit = 0;
int unit = {0};
int unit{0};
int unit(0); long double ld = 3.1415926536;
int a{ld}, b = {ld}; // 错误:转换未执行,因为存在丢失信息的危险
int c(ld), d = ld; // 正确:转换执行,且确实丢失了部分值
在函数体内部的内置类型变量将不被初始化。
变量声明
extern int i; // 声明i而非定义i
int j; // 声明并定义j
任何包含了显示初始化的声明即成为定义。
变量能且只能被定义一次,但是可以被多次声明。
用户自定义的标识符中不能连续出现两个下划线,也不能以下划线紧连大写字母开头。此外,定义在函数体外的标识符不能以下划线开头。
因为全局作用域本身并没有名字,所以当作用域操作符的左侧为空时,向全局作用域发出请求获取作用域操作符右侧名字对应的变量。
#include<iostream>
using namespace std;
int reused = 1;
int main()
{
int reused = 2; // 局部变量
::reused = 3;
reused = 4;
cout << "reused: " << reused << endl;
cout << "::reused: " << ::reused << endl; // 显示地访问全局变量 return 0;
}
引用必须被初始化
int iVal = 1024;
int &refVal = iVal; // refVal是iVal的另一个名字
无法令引用重新绑定到另外一个对象,因此引用必须初始化。
引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字。
因为引用本身不是一个对象,所以不能定义引用的引用。
除两种例外情况外,引用类型都要和与之绑定的对象严格匹配。而且,引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。
因为引用不是对象,没有实际地址,所以不能定义指向引用的指针。
现在的C++程序最好使用
nullptr
,同时尽量避免使用NULL
。把int变量直接赋给指针是错误的操作。
int zero = 0;
int *pi = zero;
赋值永远改变的是等号左侧的对象。
对于两个类型相同的合法指针,可以用相等操作符(==)或不相等操作符(!=)来比较它们,比较的结果是布尔类型。如果两个指针存放的地址值相同,则它们相等;反之它们不相等。
void*指针:
- 拿它和别的指针比较、作为函数的输入或输出
- 赋给另外一个void*指针
- 不能直接操作void*指针所指的对象
定义多个变量:
int *p1, *p2;
int* p1; int* p2;
指针是对象,所以存在对指针的引用。
默认情况下,const对象被设定为仅在文件内有效。
如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern关键字。
常量引用是对const的引用
const int ci = 1024;
const int &r1 = ci; // 正确:引用及其对应的对象都是变量
r1 = 42; // 错误:r1是对常量的引用
int &r2 = ci; // 错误:试图让一个非常量引用指向一个常量对象
初始化和对const的引用
double dval = 3.14;
const int &ri = dval; // 注意,如果ri非const就非法 /*
* 编译器把上述代码变成了如下形式:
* const int tmp = dval; // 由双精度浮点数生成一个临时的整型常量
* const int &ri = tmp; // 让ri绑定这个临时量
*/
当执行对象的拷贝操作时,顶层const不受影响,底层const的限制不能忽视。拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换。一般来说,非常量可以转换成常量,反之则不行。
常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定。
声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。
一般来说,如果你认定变量是一个常量表达式,那就把它声明成constexpr类型。
声明constexpr时使用字面值类型。算术类型、引用和指针都属于字面值类型。自定义类、IO库、string类则不属于字面值类型,也就不能被定义成constexpr。
一个constexpr指针的初始值必须是nullptr或者0,或者是存储与某个固定地址中的对象。函数体内定义的变量一般来说并非存放在固定地址中,因此constexpr指针不能指向这样的变量。相反的,定义于所有函数体之外的对象其地址固定不变,能用来初始化constexpr指针。
限定符constexpr仅对指针有效,与指针所指的对象无关。
const int *p = nullptr; // p是一个指向整型常量的指针
constexpr int *q = nullptr; // q是一个指向整数的常量指针
constexpr把它所定义的对象置为了顶层const。
与其他常量指针类似,constexpr指针既可以指向常量也可以指向一个非常量。
constexpr int *np = nullptr; // np是一个指向整数的常量指针,其值为空
int j = 0;
constexpr int i = 42; // i的类型是整型常量
// i和j都必须定义在函数体之外
constexpr const int *p = &i; // p是常量指针,指向整型常量i
constexpr int *p1 = &j; // p1是常量指针,指向整数j
类型别名:
typedef double wages;
using wages = double; typedef char *pstring;
using pstring = char*;
const pstring cstr = 0; // cstr是指向char的常量指针(注意,不能理解为const char *cstr = 0;)
const pstring *ps; // ps是一个指针,它的对象是指向char的常量指针
auto让编译器通过初始值来推算变量的类型。显然,auto定义的变量必须有初始值。
因为一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型都必须一样。
auto i = 0, *p = &i; // 正确
auto sz = 0, pi = 3.14; // 错误
使用引用其实是使用引用的对象。特别是当引用被用作初始值时,真正参与初始化的其实是引用对象的值。此时编译器以引用对象的类型作为auto的类型。
auto一般会忽略掉顶层const,同时底层const则会保留下来。
int i = 0;
const int ci = i, &cr = ci;
auto b = ci; // b是一个整数
auto c = cr; // c是一个整数
auto d = &i; // d是一个整型指针
auto e = &ci; // e是一个指向整数常量的指针(对常量对象取地址是一种底层const)
如果希望推断出的auto类型是一个顶层const,需要明确指出:
const auto f = ci;
还可以将引用的类型设为auto,设置一个类型为auto的引用时,初始值中的顶层常量属性仍然保留
auto &g = ci; // g是一个整型常量的引用,绑定到ci
auto &h = 42; // 错误:不能为非常量引用绑定字面值
const auto &j = 42; // 正确:可以为常量引用绑定字面值
要在一条语句中定义多个变量,切记,符号&和*只从属于某个声明符,而非基本数据类型的一部分,因此初始值必须是同一种类型:
auto &m = ci, *p = &ci;
decltype的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。(如:
decltype(f()) sum = x;
中sum的类型就是函数f的返回类型,但不实际调用函数f)如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内),需要指出的是,引用从来都作为其所指对象的同义词出现,只有用在decltype处是一个例外。
如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型。
- 如果该表达式的结果对象能作为一条赋值语句的左值,decltype返回一个引用类型。
- 如果表达式的内容是解引用操作,则decltype将得到引用类型。
- 如果给变量加上了一层或多层括号,编译器就会把它当成是一个表达式。变量是一种可以作为赋值语句左值的特殊表达式,所以这样的decltype就会得到引用类型。(切记:
decltype((variable))
(注意是双层括号)的结果永远是引用,而decltype(variable)
结果只有当variable本身就是一个引用时才是引用。)
赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型,如果i是int,则表达式i=x的类型是int&。
类体右侧的表示结束的花括号后必须写一个分号,这是因为类体后面可以紧跟变量名以示对该类型对象的定义,所以分号必不可少(很多新手程序员经常忘了在类定义的最后加上分号)。分号表示声明符(通常为空)的结束。一般来说,最好不要把对象的定义和类的定义放在一起。
类的数据成员定义了类的对象的具体内容,每个对象有自己的一份数据成员拷贝。
C++11规定,可以为数据成员提供一个类内初始值。对类内初始值的限制与之前介绍的类似:或者放在花括号里,或者放在等号右边,记住不能使用圆括号(因为会和函数声明混淆)。
预处理变量无视C++语言中关于作用域的规则。
《C++ Primer》笔记 第2章 变量和基本类型的更多相关文章
- C++ Primer 读书笔记 第2章 变量和基本类型
C++ Primer 第二章 变量和基本类型 2.1 基本内置类型 C++定义了一组表示整数.浮点数.单个字符和布尔值的算术类型(arithmetic type),此外还定义了Void类型. 算术类型 ...
- C++ Primer 5th 第2章 变量和基本类型
*****代码在Debian g++ 5.3.1 / clang++ 3.8(C++11)下编写调试***** 由于部分编译器对标准遵循的不同以及自身额外的扩展,本章书中的少数知识点与实际实现存在偏差 ...
- C++ Primer 笔记(2)第二章 变量与基本类型
第二章 变量与基本类型 1.基本内置类型包括算术类型和空类型,算术类型分为两类:整型(包括字符和布尔类型)和浮点型: 2.布尔类型(bool)的取值是真(true)或者假(false): 3.字面值常 ...
- C++ Primer 第2章 变量和基本类型
C++ Primer 第2章 变量和基本类型 C Primer 第2章 变量和基本类型 1 基本内置类型 算数类型 类型转换 字面值常量 2 变量 变量定义 3 复合类型 引用d左引用 指针d 4 c ...
- <<C++ Primer>> 第二章 变量和基本类型 术语表
术语表 第 2 章 变量和基本类型 地址(address): 是一个数字,根据它可以找到内存中的一个字节 别名生命(alias declaration): 为另一种类型定义一个同义词:使用 &q ...
- 《JavaScript高级程序设计》 - 读书笔记 - 第4章 变量、作用域和内存问题
4.1 基本类型和引用类型的值 JavaScript变量是松散类型的,它只是保存特定值的一个名字而已. ECMAScript变量包含两种数据类型的值:基本类型值和引用类型值.基本类型值指的是简单的数据 ...
- JavaScript高级程序设计学习笔记第四章--变量、作用域和内存问题
1.变量可能包含两种不同数据类型的值:基本类型值和引用类型值. 基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象. 2.变量复制 如果从一个变量向另一个变量复制基本类型的值,会在 ...
- 【c++ Prime 学习笔记】第2章 变量和基本类型
2.1 基本内置类型 基本数据类型包含了算术类型(arithmetic type)和空类型(void) 算数类型,包含了字符.整型数.布尔值和浮点数 空类型,不对应具体的值 2.1.1 算术类型 算术 ...
- C和指针 第三章 变量的储存类型 auto、static、register以及static关键词
变量的储存类型决定标量何时创建,何时销毁以及他的值保持多久.有三个地方可以储存变量: 普通内存static 运行时堆栈auto 硬件寄存器register 变量的缺省储存类型取决于它的声明位置: 静态 ...
随机推荐
- Codeforces Round #686 (Div. 3) E. Number of Simple Paths (思维,图,bfs)
题意:有一个\(n\)个点,\(n\)条边的图,问你长度至少为\(1\)的简单路径有多少条. 题解:根据树的性质,我们知道这颗树一定存在一个环,假如一棵树没有环,那么它的所有长度不小于\(1\)的简单 ...
- 牛客练习赛63 C.牛牛的揠苗助长
题意:有一个长度为\(n\)的数组,从第一天开始,第\(i\)天可以使\(i\)位置上的数\(+1\),当\(i=n\)时,下次从\(i=1\)再开始,另外,在每天结束时,你可以使任意一个位置上的数\ ...
- 设计模式(十八)——观察者模式(JDK Observable源码分析)
1 天气预报项目需求,具体要求如下: 1) 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方). 2) 需要设计开放型 API,便于其他第三方也能接入气象 ...
- C#Assembly、程序集、装配件、命名空间以及类型的关系
Assembly = 程序集 = 装配件 命名空间是类的逻辑组织形式,程序集是类的物理组织形式. 程序集其实和命名空间没有什么必然的联系. 程序集1: namespace1{ public class ...
- C++实现二叉树的基本操作:建立、遍历、计算深度、节点数、叶子数等
题意: 代码实现: #include<iostream> #include<queue> #include<stack> using namespace std; ...
- Kubernets二进制安装(10)之部署主控节点部署调度器服务kube-scheduler
Kubernetes Scheduler是一个策略丰富.拓扑感知.工作负载特定的功能,调度器显著影响可用性.性能和容量.调度器需要考虑个人和集体的资源要求.服务质量要求.硬件/软件/政策约束.亲和力和 ...
- C++ part3
函数和const references: C++中const用于函数重载 有些情况可以重载,有些不行,具体看↑. 隐式类型转换 references: nowcoder 对于内置类型,低精度的变量给高 ...
- python文件持久化存储
文件持久化存储 目录 文件持久化存储 脑图 文件的操作 with 语句 OS模块 json模块 存储为Excel文件 脑图 文件的操作 import os import platform # 1. 获 ...
- Ubuntu 18.04 + pip3 install virtualenvwrapper 报错 ERROR: virtualenvwrapper could not find virtualenv in your path
接上片... 问题 virtualenvwrapper装好后, 发现使用mkvirtualenv XX时, 又找不到virtualenv了... apt install python3-virtual ...
- Taro 3.x in Action
Taro 3.x in Action React, 小程序 https://taro-docs.jd.com/taro/docs/README Taro Next 跨端, 跨框架 Taro 是一个开放 ...