c++primer 第2章 变量和基本类型

  • 第Ⅰ部分 c++基础

    • 语法特征

      • 类型 变量 语句 控制结构 函数
      • 补充:自定义数据类型(语言扩展);功能封装成库函数
    • c++ 静态数据类型语言 类型检查发生在编译时

    • c++类 包含 数据成员 函数成员

第2章 变量和基本类型

  • 数据类型:数据意义 操作

  • 内置类型: 字符 整型 浮点型

2.1 基本内置类型

  • 算术类型(字符 整型 布尔型 浮点型 ) 空类型

2.1.1 算术类型

  • 整型(包括字符和布尔) 浮点型
类型 含义 最小尺寸
bool 布尔类型 /
char 字符 8
wchar_t 宽字符 16
char16_t Unicode字符 16
char32_t Unicode字符 32
short 短整型 16
int 整型 16
long 长整型 32
long long 长整型 64
float 单精度浮点型 6位有效数字
double 双精度浮点型 10位有效数字
long double 扩展精度浮点型 10位有效数字
  • char 空间确保可存放机器基本字符集任意字符对应数字值

  • wchar_t char16_t char32_t 确保可存放机器最大扩展字符集任意字符
     

  • 赋予内存中某地址明确含义需知道存储在地址的数据类型,类型决定数据所占比特数/解释比特内容

  • 浮点型 :单/双/扩展精度浮点型 float 1个字32bit;double 2个字64bit;long double 3/4个字96/128bit

  • 带符号类型 无符号类型
    • (除去 布尔型 扩展字符型)整型可分 带/无符号类型
    • 带符号:正、负、0;无符号:大于0
    • int short long ,long long 均为带符号,加unsigned为无符号;unsigned int 可简写为unsigned
    • 字符型:char(实际上会为后两种的其中一种由编译器决定)、signed char、unsigned char
    • unsigned char可表示0-255区间内的值,signed char表示范围-128-127
  • 如何选择类型
    • 明确值不可能为负时选无符号类型
    • 整数运算用int,超出int范围用long long
    • 算数表达式不使用char/bool
    • 浮点数运算用double(float精度不够/计算代价相差不大)

2.1.2 类型转换

  • 类型所能表示的值得范围决定了转换的过程
    • 非bool->bool: 0->false; other->ture
    • bool->非bool:false->0; ture->1
    • 浮点->整型:仅保留小数点前部分
    • 整型->浮点:小数部分记为0,若超出浮点类型容量则精度可能有损失
    • 给无符号赋超出范围的值->初始值对无符号类型表示数值总数取模后的余数
    • 给带符号类型赋超出表示范围的值,结果为未定义
  • 避免无法预知(编译器无需/不能检测的错误)和依赖于现实环境的行为
  • 含有无符号类型的表达式
    • 负数和无符号数相加,先将负数转换为无符号数类似直接给无符号数赋一个负值,结果等于这个负数加上无符号数的模
    • 从无符号数减去一个值(无论是不是无符号数),须确保结果不能是一个负值
    • 循环中的条件,for不要写无符号数>=0;因为其永远也不会小于0,会导致死循环;改用while(u>0){–u;}
  • 切勿混用带符号类型和无符号类型
    • 带符号数会自动转换为无符号数

2.1.3 字面值常量

  • 整型和浮点型字面值
    • 0开头八进制,0x开头16进制
  • 字符和字符串字面值
    • 单引号字符字面值’a’
    • 双引号字符串字面值"a"(常量字符构成的数组array,编译器在字符串结尾添加’\0’,故长度比内容多一;可以分行书写"hello"“world”)
  • 转义序列
    • 不能直接使用:1. 不可打印;2. 特殊含义字符:单引号 双引号 问号 反斜线
    • 换行 \n 横向制表\t 纵向制表\v 退格\b 双引号\" 反斜杠\\ 回车\r …
    • 泛化的转义序列 \x后跟一个或多个16进制数字,\后跟1/2/3个八进制数字
  • 指定字面值的类型(前缀(字符和字符串字面值)u,U,L,u8;后缀(整型/浮点型字面值)U,L,LL, F,L)
  • 布尔字面值和指针字面值
    • 布尔:true false ;指针:nullptr

2.2 变量

  • 具名的 可供操作的储存空间;数据类型决定变量所占内存空间大小和布局方式,存储值的范围,能够参与的运算;变量和对象可以互换使用

2.2.1 变量定义

  • 类型说明符 变量名(变量名以逗号分隔 以分号结束)
  • 对象:一块能存储数据并具有某种类型的内存空间
  • 初始值:创建变量时获得的特定值(初始化);初始化不是赋值,赋值:把对象的当前值擦除而以一个新值替代
  • 列表初始化int a=0;int a={0};int a{0};//花括号列表初始化 int a(0);
  • 默认初始化:定义时没指定初值变量被默认初始化;内置类型定义于函数体外初始化为0,定义于函数体内则不被初始化。(建议初始化每一个内置类型变量)

2.2.2 变量声明与定义的关系

  • 分离式编译:将程序分割为若干个文件,每个文件可被独立编译
  • 声明:使名字为程序所知(规定变量的类型和名字)(extern);定义:负责创建与名字关联的实体(规定变量的类型和名字外还申请储存空间/可能为变量赋初始值);任何包含显式初始化的声明即成为定义;函数体内部试图初始化extern关键字标记的变量将引发错误;变量只能被定义一次但可被多次声明
  • c++静态类型语言,编译阶段检查类型

2.2.3 标识符

  • 字母 数字 下划线组成,必须以字母或者下划线开头;长度无限制,大小写敏感
  • 不能被用作标识符:保留字,标准库保留名字(连续两个下划线/下划线紧连大写字母开头),定义在函数体外标识符不能以下划线开头
  • 变量命名规范:
    • 标识符要体现实际含义
    • 变量名一般用小写字母
    • 自定义类名以大写字母开头
    • 标识符由多单词组成,单词间应明显区分(下划线或驼峰)

2.2.4 名字的作用域

  • c++作用域以花括号分割
  • 名字有效区域:始于名字声明语句,终于声明语句所在作用域末端
  • 全局作用域:定义在函数体外(花括号外);块作用域
  • 建议第一次使用变量时再定义它
  • 嵌套的作用域
    • 内层作用域:被包含(被嵌套)的作用域 (允许内层作用域中重新定义外层作用域已有的名字)
    • 外层作用域:包含着别的作用域的作用域
  • 局部变量正在作用域内(in scope)会覆盖全局变量;域操作符左侧为空如 ::g_cat即为全局作用域对应变量

2.3 复合类型

  • 基于其他类型定义的类型:引用 指针
  • 声明语句: 数据类型 变量名;基本数据类型 声明符列表

2.3.1 引用(左值引用)

  • 为对象另起一个名字,定义引用&(必须初始化)时,程序将引用和初始值绑定而不是拷贝;引用本身不是对象不能定义引用的引用;引用只能绑定在对象上,不能与字面值或表达式计算结果绑定在一起

2.3.2 指针

  • 指向另外一种类型的符合类型(存放某个对象的地址);
  • 和引用的不同
    • 指针本身是一个对象,允许指针赋值和拷贝,可以先后指向不同的对象;
    • 指针无须在定义时赋初值
  • 获取对象地址
    • 使用取地址符&
    • 除两例外情况外,指针类型都要与指向对象严格匹配
  • 指针值(地址)
    • 指向一个对象
    • 指向紧邻对象所占空间的下一个位置
    • 空指针
    • 无效指针
  • 利用指针访问对象
    • 使用解引用符(*)(仅适用于指向某个对象的有效指针)访问对象,给解引用的结果赋值,实际上就是给指针所指的对象赋值
  • 在声明语句中,&*用于组成复合类型(引用 指针);在表达式中他们转变成运算符(取地址 解引用)
  • 空指针
    • 不指向任何对象,使用指针前先检查其是否为空
    • 初始化(nullptr(最好使用nullptr),0,NULL(尽量避免))
    • 不能把int型变量直接赋值给指针 变量值恰好为0也不行
  • 建议初始化所有指针
  • 赋值和指针
    • 定义引用后无法令其再绑定到另外的对象
    • 给指针赋值令它存放一个新的地址,指向新的对象
    • 赋值永远改变的是等号左侧的对象
  • 其他指针操作
    • 任何非0指针的条件值都是true
    • == 指针存放的地址值相同:都为空;都指向同一个对象;都指向同一对象的下一地址
  • void*指针
    • 可用于存放任意(类型)对象的地址
    • 与别的指针比较;作为函数输入输出;赋给另外一void指针;不能直接操作void指针所指对象

2.3.3 理解复合类型的声明

  • 一条定义语句可能定义出不同的数据类型,如int 1=1024,*p=&i,&=i;
  • 定义多个变量
    • 类型修饰符&*,对声明语句中的其他变量不产生任何作用。建议将&*与变量名连在一起
  • 指向指针的指针
    • 指针本身也有自己的地址,**表示指向指针的指针, ***表示指向指针的指针的指针
  • 指向指针的引用
    • 引用本身不是对象,不能定义指向引用的指针,但存在对指针(是对象)的引用int *p;int *&r=p;
  • 面对比较复杂的指针或者引用的声明语句使,从右向左阅读有助于弄清楚其真实含义

2.4 const限定符

  • const对象一旦创建后值就不能再改变,必须初始化
  • 初始化和const 只能在const类型的对象上执行不改变其内容的操作
  • 默认状态下 const对象尽在文件内有效,多文件共享方法:const变量不管是声明还是定义都添加extern关键字

2.4.1 const的引用

  • 对常量的引用:引用及其对应的对象都是常量const
  • 引用的对象是常量还是非常量都不会影响引用和对象的绑定关系
  • 初始化和对const的引用 引用类型和引用对象类型应一致的两个例外:初始化常量引用时允许用任意表达式作为初始值,只要表达式结果能转换为引用类型即可(绑定临时量对象);
  • 对const的引用可能引用一个并非const对象int i=42;const int &r2=i;i可以改变,但不允许通过r2修改i的值

2.4.2 指针和const

  • 想要存放常量对象的地址,只能使用指向常量的指针

  • 指针类型必须与其所指向的对象的类型一致,两个例外:

    • 允许另一个指向常量的指针指向一个非常量对象,但不能通过该指针修改变量的值
    • 指向常量的指针或者引用,自以为是,觉得自己指向了常量,自觉不去修改对象的值
  • const指针

    • 常量指针必须初始化,一旦初始化,它的值(存放的地址)就不允许改变
      • *在const之前说明指针是个常量(常量指针),指针的指向不能改变
      • *在const之后说明指针指向的值是个常量(指针常量),指针指向的值不能改变

2.4.3 顶层const

  • 顶层const 指针/任意对象本身是个常量
  • 底层const 指针所指向的/引用对象是个常量(用于声明引用的const都是底层const)
  • 对象的拷贝操作,顶层const(被拷贝对象)不受什么影响,底层const拷入和拷出的对象必须具有相同的底层const资格/两对象的数据类型必须能够转换;非常量可以转换为常量反之不行

2.4.4 constexpr和常量表达式

  • 常量表达式:值不会改变并且在编译过程中就能得到计算结果的表达式(如 字面值 用常量表达式初始化的const对象)
  • constexpr变量:将变量声明为constexpr以便由编译器来验证变量的值是否是一个常量表达式;若认定变量是一个常量表达式就将其声明成constexpr类型
  • 字面值类型:算术类型 引用 指针; 不属于字面值类型: 自定义类 IO库 string
    • constexpr指针的初始值必须是nullptr/0/存储于某个固定地址中的对象
  • 指针和constexpr:constexpr限定符仅对指针有效,与指针所指的对象无关,constexpr将其所定义的对象置为顶层const

2.5 处理类型

  • 复杂性:难拼写 不清楚需要的类型是什么

2.5.1 类型别名

  • 某种类型的同义词
  • 定义类型别名方法
    • 关键字typedef
    • 别名声明:关键字using
  • 指针 常量 类型别名
    • 不能直接将类型别名替换成它本来的样子
    typedef char *pstring;
    //声明了一个指向char的常量指针
    const pstring cstr=0;
    //上行不能直接替换成 
    const char *cstr=0; //指向const char的指针
    

2.5.2 auto类型说明符

  • 让编译器通过初始值来推算变量的类型
  • 一条声明语句中只能有一个基本数据类型,同一条auto语句中所有变量的初始基本数据类型都必须一致
  • 复合类型 常量 和 auto
    • auto一般会忽略顶层const,保留底层const;如果希望推断出的auto是顶层const须明确指出 即在auto前加const
    • 设置一个类型为auto的引用时,初始值中的顶层常量属性仍然保留
    • &和*只从属于某个声明符而非数据类型的一部分 因此初始值必须是同一种类型

2.5.3 decltype

  • 选择返回操作数的数据类型,编译器分析表达式并得到它的类型,却不实际计算表达式的值
  • decltype处理顶层const和引用的方式与auto不同,若decltype使用的表达式是一个变量则decltype返回该变量的类型(包括顶层const 和引用在内)
  • decltype和引用
    • 引用类型作为表达式的一部分结果将是一个具体值而非引用
    • 若表达式内容是解引用操作,decltype将得到引用类型
    • decltype((variable))的结果永远是引用

2.6 自定义数据类型

  • 数据结构:把一组相关的数据元素组织起来然后使用它们的策略和方法,c++允许用户以类的形式自定义数据类型

2.6.1 定义Sales_data类型

  • struct 类名 类体(花括号{}包围形成一个新的作用域) 分号;
  • 类数据成员 类内初始值 没有初始化的成员将被默认初始化

2.6.2 使用Sales_data类

  • 添加类对象
  • 对象读入数据(使用点操作符.读入对象成员)
  • 输出两个对象的和

2.6.3 编写自己的头文件

  • 头文件通常只包含那些只能被定义一次的实体 如类/const/constexpr
  • 预处理器概述(确保头文件多次包含仍能安全工作)
    • 编译之前执行的一段程序 可部分的改变我们写的程序
    • 头文件保护符 依赖于预处理变量
      • #define 将一个名字设定为预处理变量
      • #ifdef 变量已定义为真
      • #ifndef 变量未定义时为真
      • 一旦检查结果为真,执行后续操作直到遇到#endif指令为止
  • 预处理变量无视c++中关于作用域的规则
  • 预处理变量包括头文件保护符必须唯一 一般预处理变量名字全部大写
  • 一般习惯性加上头文件保护符

小结

  • 类型 分为非常量和常量 常量对象必须初始化,一旦初始化就不能再改变
  • 复合类型(以其他类型为基础) 指针 引用
  • 以类的形式自定义类型,c++库提供高级抽象类型如string

术语表

address alias declaration arithmetic type array auto base type
bind byte class member compound type const const pointer
const reference const experession constexpr conversion data member declaration
declarator decltype default initiatialization defintion escape sequence global scope
header guard identifier in-class initializer in scope initialized inner scope
integral type list initialization literal literal local scope low-level const
member nonprintable character null pointer nullptr object outer scope
pointer pointer to const preprecessor reference reference reference to const
scope class namespace block separate compilation signed
string struct temporary top-level const type alias type checking
type specifiler typedef undefined uninitialized unsigned variable
void* void word & operator * operator #define
#endif #ifdef #ifndef

猜你喜欢

转载自blog.csdn.net/m0_68312479/article/details/128401080