美文网首页
[C++ Primer]第二章 变量与基本类型

[C++ Primer]第二章 变量与基本类型

作者: 两全丶 | 来源:发表于2018-09-18 17:27 被阅读0次

    2.1 基本内置类型

    包括

    • 算术类型
    • 空类型(void)

    2.1.1 算术类型

    • 整型
      包括了char和bool
    • 浮点型

    算术类型所占的大小在不同机器上有所差别

    类型 h含义 最小尺寸(字节)
    bool 未定义
    char 1
    wchar_t 宽字符 2
    char16_t Unicode字符 2
    char32_t Unicode字符 4
    short 2
    int 2
    long 4
    long long 8
    float 6位有效数字
    double 10位有效数字
    long double 10位有效数字

    带符号类型和无符号类型

    • singed
    • unsinged
      只能表示大于等于0的数

    对于char(注意)

    • char
      具体为有符号还是无符号由编译器决定
    • singed char
    • unsigned char

    类型选择的建议

    • 非负选用unsigned
    • 若数值超过了int的范围,选用long long, 因为long一般情况下和int大小一样
    • char不要用于算术运算, 因为它在有些机器上是有符号的,一些是无符号的
    • 浮点运算用double, float精度不够,且通常float和double的计算代价相差不大

    2.1.2 类型转换

    • bool \rightarrow 非bool类型
      • true \rightarrow 1
      • false \rightarrow 0
    • 非bool类型 \rightarrow bool
      • 0 \rightarrow false
      • 非0 \rightarrow true
    • 赋给无符号数超出范围的值
      结果为该值对能表示的最大值取模后的余数
    • 赋给有符号数超出范围的值
      结果是未知的

    含有无符号类型的表达式

    • 同时含有无符号类型和有符号类型的时候,有符号类型会转换成无符号类型
    • 从无符号数中减去一个数,必须保证结果非负
    • 无符号数做for循环计数变量也会出现问题
      当u为0时,--u得到的是取模后的余数,为正数,而不会是-1
    for(unsigned int u = 10;u >= 10;--u)
      cout << u << endl;
    //改为
    while(u > 0)
    {
      u--;//必须先减再输出
      cout << u << endl;
    }
    

    2.1.3 字面值常量

    每个字面值常量都对应一种数据类型,字面值常量的形式和值决定了它的数据类型

    整型和浮点型字面值

    整型

    • 进制问题
      • 20---十进制
      • 024---八进制(0开头)
      • 0x14---十六进制(0x开头)
    • 符号问题
      • 十进制字面值是带符号数
      • 八进制和十六进制数字面值可能是带符号数也可能是无符号的
    • 类型问题
      • 十进制字面值为int, long, long long中能容下它的最小的一个
      • 八进制和十六进制字面值为int, unsigned int, long, unsigned long, long long, unsigned long long中能容纳其数值的最小的一个
      • short没有字面值

    浮点型

    • 浮点型字面值是double

    字符和字符串字面值

    • 字符字面值

      ‘a’

    • 字符串字面值

      "abc"

    转义序列

    常用的有

    • \n换行
    • \t制表符

    指定字面值的类型

    字符和字符串字面值前缀

    前缀 含义 类型
    u Unicode16字符 char16_t
    U Unicode32字符 char32_t
    L 宽字符 wchar_t
    u8 UTF-8字符串(用于字符串) char

    整型浮点型字面值后缀

    后缀 含义 类型
    u or U unsigned能匹配的最小类型 无符号
    l or L 至少为long long
    ll or LL 至少为long long long long
    f or F float float
    l or L(浮点型) long double long double

    布尔字面值和指针字面值

    布尔

    • true
    • false

    指针

    • nullptr

    2.2 变量

    2.2.1 变量定义

    初始值

    double price = 109.99;
    

    列表初始化(C++11)

    //等价于 int sold = 0;
    int sold = {0};
    int sold{0};
    int sold(0);
    

    默认初始化

    • 内置类型的全局变量

      初始化为0

    • 内置类型的局部变量

      不被初始化

    2.2.2 变量声明和定义的关系

    为了支持分离式编译(拆分为多个文件), C++将声明和定义区分开来。要在多个文件里使用同一个变量,必须将声明和定义分离。

    声明(Declaration)

    使得名字为程序所知(可以声明别处定义过的变量,进行使用)

    定义(Definition)

    负责创建与名字关联的实体

    extern int i; //只声明而不定义i
    int j; //声明并且定义j
    extern double pi = 3.14 //extern语句如果包含初始值就不再只是声明,包括了定义(函数体内部这么做会报错)
    

    2.2.3 标识符

    • 不能为保留字
    • 必须以下划线或者字母开头
    • 不能连续出现两个下划线
    • 不能下划线紧接着大写字母开头
    • 定义在函数体外的标识符不能以下划线开头

    2.2.4 名字的作用域

    • 定义于所有花括号之外的为全局作用域

      在整个程序范围内都可以使用

    • 定义在花括号内拥有块作用域

      只在该花括号内有效

    • 嵌套的作用域

      int a = 1;
      void func1()
      {
          int a = 2;
          cout << a << endl;
          //输出2,内层覆盖外层作用域
          cout << ::a << endl;
          //输出1,使用域操作符来使用全局变量
      }
      

    2.3 复合类型

    复合类型指基于其他类型定义的类型。

    2.3.1 引用

    引用为对象其了另外一个名字。使用&d来定义引用类型

    int a = 100;
    int &ref = a;//ref 指向 a
    //int &ref;错误,引用必须被初始化
    
    • 引用必须被初始化(绑定)

    • 无法令引用重新绑定到另外一个对象

    • 引用本身不是一个对象, 不能定义引用的引用

    • 引用的类型必须与其绑定的对象严格匹配

    • 引用只能绑定在对象上,不能绑定在字面值上

      int &ref = 10;//错误
      

    2.3.2 指针

    指针是指向另外一种类型的复合类型,通过*d来定义

    int a = 1;
    int *pointer = &a;
    

    指针与引用的区别

    • 指针本身是一个对象
    • 指针可以先后指向不同的对象
    • 指针不需要赋初值
    • 由于引用不是对象, 所以不能定义指向引用的指针

    获取对象的地址

    通过取地址运算符&

    指针也需要与其被指对象的类型严格匹配(有两个例外的情况)

    int a = 1;
    int *pointer = &a;//取地址运算符&
    

    空指针与野指针

    • 空指针即为nullptr,不指向任何对象

      int *p1 = nullptr;//为C++11新标准
      int *p2 = 0;//也是空指针
      int *p3 = NULL;//NULL是一个预处理变量,不属于命名空间std,由预处理器负责管理,可以直接使用
      
    • 野指针即未被初始化的指针(指向未知地址)

    利用指针访问对象

    使用解引用符*

    int a = 1;
    int *pointer = &a;//取地址运算符&
    cout << *pointer << endl;
    

    其他指针操作

    • 非空指针可以转化为true, 空指针转化为false

      int *p1 = nullptr;
      if(p1)
      {
          cout << "p1 is not nullptr" << endl;
      }
      
    • 指针比较

      通过==来比较两个指针(两个指针都为空,也是相等)

    void*指针

    可以存放任意类型对象的地址,但是在使用时必须进行类型转换才能使用

    int a = 1;
    void *p1 = &a;//合法
    cout << *p1 << endl;//不合法
    int *p2 = (int *)p1;
    cout << *p1 << endl;//合法
    

    2.3.3 理解复合类型的声明

    变量的声明

    • 由基本数据类型 + 声明符组成,声明符中可以加上类型修饰符
    int *p;
    int a;
    int &ref = a;
    // *, &在这里为类型修饰符
    

    指向指针的指针

    通过*的个数来区别指针的级别

    int a = 1;
    int *pi = &a;//一级指针
    int **pii = &pi;//二级指针
    //也是由于使用了不同的类型修饰符
    

    绑定指针的引用

    由于指针是对象,所以可以用引用绑定指针

    int i = 42;
    int *p = &i;
    int *&ref = p;//绑定int *指针的引用
    

    2.4 const限定符

    const限定符用来声明常量值

    • const变量一旦声明不可改变值
    • const变量必须赋初值
    const int bufsize = 512;
    

    const作用域

    默认情况下,const对象仅在文件内有效

    若想要让const对象在其他文件中也能访问到,必须在定义和声明时都添加extern关键字

    extern const int bufsize = 125;//定义也要加上extern
    
    extern const int bufsize;//声明加上extern
    

    2.4.1 const的引用

    可以将const对象绑定到引用上, 但是该引用必须也用const修饰

    const int a = 125;
    const int &ref = a;
    

    初始化和对const的引用

    在两种情况下,引用绑定的对象可以不和引用类型匹配

    • 常量引用绑定的对象能够转化为引用的类型
    • 允许一个常量引用(注意必须是被const修饰的引用)绑定非常量对象
    int i = 42;//非常量对象
    const int &ref1 = i;//绑定非常量对象,注意必须为const
    double dval = 3.14;//浮点数
    const int &ref2 = dval;//绑定类型不匹配的对象,但是浮点数可以转化为int
    /*
    实际上发生的事情为,创建了一个临时变量,该引用绑定到了该临时变量上
    如果该引用不是const的,修改该引用修改的是临时变量,而不是原来的变量,所以必须为const的
    const int temp = dval;
    const int &ref2 = temp;
    */
    

    2.4.2 指针和const

    类似于常量引用,一样可以定义指向常量的指针,但是指针必须用const修饰

    const double pi = 3.14;
    double *ptr = &pi; //错误,必须用const修饰
    const double *ptr = &pi;
    

    const指针

    代表的意思为不能改变该指针所指向的对象.注意const的位置

    int *const pointer;
    

    const指针必须初始化

    int a = 0;
    int b = 0;
    const int *ptr = &a;
    ptr = &b; //错误
    

    2.4.3 顶层const

    顶层const

    对于指针来说表示指针本身是个常量

    一般的,顶层const可以表示任意的对象是常量

    底层const

    对于指针来说表示指针所指的对象是个常量

    一般的,底层const则与指针和引用等符合类型的基本类型部分有关(所指的东西)

    2.4.4 constexpr和常量表达式

    常量表达式指不会改变,且在编译过程中就能计算得到的表达式

    • 字面值是常量表达式
    • 常量表达式初始化的const对象也是常量表达式

    constexpr常量

    c++11新标准规定, 可以用constexpr来声明一个常量表达式变量(是一个常量)

    constexpr int mf = 20; //是常量表达式
    constexpr int m1 = size();//不是常量表达式,不行
    

    字面值类型

    • 自定义类, IO库, string类型不属于字面值类型不能定义为constexpr
    • 指针类型变量要定义为constexpr必须满足
      • 要么被初始化为nullptr
      • 要么是存储于某个固定地址中的对象
        • 定义于函数体内的变量一般来说不是存储在固定的地址
        • 定义于所有函数体外的对象地址固定不变

    指针和constexpr

    用constexpr修饰指针,表达的意思使该指针为常量指针(即该指针本身不能改变)

    2.5 类型别名

    使用类型别名可以简化类型书写

    2.5.1 类型别名

    typedef

    typedef double wages; //wages i = 0.0; 即为声明一个double类型的变量
    typedef int *p;//p为int *的同义词
    typedef int p[10];//p为int arr[10]的同义词
    

    别名声明(c++11)

    using SI = Sales_item; //SI是Sales_item的同义词
    

    指针、常量和类型别名

    typedef int *p;//p为int *的同义词
    const p i = 0; //i为指向char的常量指针(注意不是指向常量 的指针)
    

    不能简单的将类型别名替换为他原来的名字

    const int *i = 0;//这就变成了指向const int常量的指针了,而不是常量指针
    

    2.5.2 auto类型说明符

    C++11新标准允许用auto类型说明符让编译器替我们去分析表达式所属的类型

    int i1 = 0;
    float i2 = 1.2;
    auto var = i1 + i2;//var为float
    

    复合类型、常量和auto

    编译器推断出来的类型和初始值类型有时不完全一样,编译器会做适当的调整

    • 使用引用来初始化时,会使用被引用的对象的类型作为auto的类型

      int i = 0, &r = i;
      auto a = r;//a的类型为int 而不是 int &
      
    • auto会忽略顶层const, 保留底层const

      const int ci = i, &cr = ci;
      auto b = ci;//b为int, 忽略了顶层const
      auto c = cr;//c为int, cr为引用这时候要看所引用对象,而const int ci为顶层const所以忽略const
      auto d = &i;//d为int *
      auto e = &ci;//e是const int * ???????这里不怎么理解
      

    如果希望推断出auto类型为顶层const,可以加上const

    const auto f = ci;
    

    还可以将引用类型设置为auto

    auto &g = ci;
    

    2.5.3 decltype类型指示符

    相关文章

      网友评论

          本文标题:[C++ Primer]第二章 变量与基本类型

          本文链接:https://www.haomeiwen.com/subject/jgipnftx.html