【C++Primer笔记】第二章 变量和基本类型

从本章节开始进入第一部分:C++基础!

数据类型决定着变量所占内存空间大小、该空间所能存储的值的范围,以及变量能参与的运算。

算术类型

  1. 基本内置类型使用法则

    • 数值确定不为负,用unsigned
    • 使用int进行整数运算。如果大于int(216=65536, 28=32768),使用long long型(字面值末尾加LL);
    • 在算术表达式中不要用charboolchar是否有符号视机器而定,而bool无论赋值为多少,转换为整型都是0或1);
    • 执行浮点数运算用double(单精度6位,双精度10位)。
  2. 赋给无符号类型一个超出它表示范围的初始值时,结果是初始值模表示数值总数后的值(如unsigned char类型的-1相当于模256后的255).而赋给有符号类型一个超范围的值时,结果是未定义的。一个算术表达式中既有无符号数又有int时,后者会自动转换为无符号数。切勿混用带符号类型和无符号类型!

  3. 20 //20十进制
    024 //20八进制
    0x14 //20十六进制
    
  4. 转义序列:反斜线、问号、双引号、单引号前面都要加\。

    泛化的转义序列:\x后面跟一个十六进制数字,或者\后面跟一个不超过三位的八进制数字。

定义和声明

  1. 使用列表初始化时,如果初始值存在丢失信息的风险,编译器会报错。

    double val = 3.141592653;
    int a = {val}; //报错
    int b = val; //不报错
    
  2. **定义于任何函数体之外的变量被初始化为0(包括main函数),而定义在函数体内部的内置类型变量不被初始化。**不被初始化的变量,值是未定义的(Codeblocks里是随机数)。建议初始化每一个内置类型变量。

  3. 如果要在多个文件中使用同一个变量,就必须把声明和定义分离:在一个文件中定义变量(不一定要加extern),而在其他文件中对其进行声明。

    extern int i; //不能初始化,否则则为定义
    
  4. **当你第一次使用变量时,再去定义它!**在内层作用域中,可以重新定义外层作用域已有的名字。这样,前者会覆盖后者。再次访问后者需要使用::操作符。如果函数可能用到一个全局变量,则不应再定义一个同名的局部变量。

引用和指针

  1. 复合类型:引用和指针。**引用只是为一个已有对象起的别名,本身并不是对象(而指针本身是一个对象)。引用无法解绑,必须初始化(和指针不同)。引用、指针类型必须和对象类型严格匹配。**定义方式如下:

    int *p1, p2, &r3;
    //p1是指针,p2是int型对象,p3是引用
    
  2. 只有有效指针才能解引用。void*型指针可以存放任意类型对象的地址,但不能解引用,只能用作函数输入输出、和其他指针比较,或者赋值给另一个void*指针。

  3. 空指针:

    int *p1 = nullptr; 
    int *p2 = 0;
    
  4. 等定义对象后再定义指向它的指针。若实在不知道指针指向何处,就初始化为nullptr

  5. 赋值改变的是永远是等号左侧的对象!

  6. 不存在指向引用的指针(因为引用不是对象),但是存在对指针的引用:

    int val = 32;
    int *p = &val;
    int *&r = p; //r是一个对指针p的引用
    

Const

  1. 凡是定义后不能更改的变量必须初始化。如const型变量、引用变量。

  2. const对象默认情况下只在文件内有效。如果要多个文件共用,定义和声明时都要加extern

  3. 允许一个对const的引用(常量引用)绑定非常量对象、字面值、表达式。而普通引用无法绑定到常量对象或常量引用身上。虽然不能修改常量引用的值,但仍能通过其他途径修改被引用的对象。

    int i = 42;
    const int &r = i;
    i = 0;
    r = 1; //错误!
    
  4. 指向常量的指针与常量引用类似(底层const):只是不能通过解引用修改指向的对象而已,通过其他途径修改还是可以的。但是这种指针可以不用初始化,也可以改变它的指向。

  5. 常量指针本身是一个常量,所以必须初始化,且不能修改其值(地址)。还是可以通过从右往左原则记忆(最右边的代表其属性)。

    int i;
    const int *i1; //指向常量的指针
    int *const i2 = &i; //常量指针
    
  6. 对顶层const(普通、常量指针)的拷贝没有限制。而对于底层const(常量引用和指向常量的指针),只能常量之间拷贝,或者非常量转换为常量。

Constexpr

  1. 只有包含const修饰符、初始值为字面值类型(或为用常量表达式初始化的const对象)的表达式才是常量表达式(注:字面值类型包括整型(包括布尔型和字符型)、浮点型、引用和指针)。

    const int max = 100; //max是常量表达式
    const int limit = max + 1; //limit是常量表达式
    int is = 27; //is不是常量表达式
    const int s = getSize(); //s不是常量表达式
    
  2. 声明为constexpr的变量(顶层const)一定是一个常量。如果认定一个变量是常量表达式,就把它声明为constexpr

  3. constexpr指针只能初始化为nullptr或常量的地址。不过,由于定义于所有函数之外的变量的地址固定不变,它们是可以用来初始化constexpr指针的。注意写法:

    constexpr int *p = 0; //和指向常量的指针是完全不同的!
    

处理类型

typedef

  1. 类型别名的声明方法:

    typedef double wages; //传统方法
    typedef wages base, *p; //p是double*类型
    // using wages = double; //C++11的新方法
    

    注意:

    typedef char *p;
    const p cspr = 0; //cspr是一个常量指针,而不是指向常量的指针
    

auto

  1. auto类型说明符能让编译器自主判断类型。显然,auto定义的变量必须初始化。一条声明语句中所有变量的初始基本数据类型必须相同。

    double val1, val2;
    auto val = val1 + val2; //由右侧的表达式推出val是double型
    auto sz = 0, pi = 3.14; //错误!
    
  2. auto默认会忽略掉引用和顶层const特性:

    int i = 0, &r = i;
    auto a = r; //a是整型变量,而非对整型的引用
    const int ci = i, &cr = ci;
    auto b = ci; //b是整型变量(顶层const)
    auto c = &cr; //c是指向整型常量的指针(底层const)
    
  3. 如果想要推出顶层const型,要在auto前面加上const

  4. 设置一个类型为auto的引用时,初始值中的顶层属性仍然保留,且原来的初始化规则仍然适用。

    auto &g = ci; //g是一个整型常量引用
    auto &h = 42; //错误!不能为非常量引用绑定字面值
    const auto &j = 42; //正确!
    

decltype

  1. decltype()返回操作数的数据类型(当你想知道这个表达式的数据类型,而又不想用这个表达式的值作为初始值的时候,用decltype而不用auto)。

  2. decltype返回的类型包括引用和顶层const在内(引用从来都只作为其引用对象的同义词(代名词)出现,只有在decltype是个例外)。

  3. 一些使用法则:

    int i = 32, *p = &i, &r = i;
    decltype(r+0) b; //正确!使用加法后变为整型,而非整型引用
    decltype(*p) c; //错误!指针解引用后返回引用类型,要初始化
    decltype((i)) d; //错误!两个括号得到引用类型
    

自定义数据结构

  1. 建议定义分开写,不要合在一起:

    struct Data{...};
    Data d1, d2;
    
  2. 头文件通常包含类、const变量、constexpr变量等。

  3. 头文件保护符:为了防止重复定义某一头文件。

    #ifndef SALES_DATA_H //如果还没被定义过
    #define SALES_DATA_H //定义
    #include <string> 
    //string头文件里也写了头文件保护符,就不会被重复定义
    struct SalesData {
    	std::string bookName;
    	double revenue = 0.0;
    };
    #endif
    

我的问题

auto &s1 = "demo";
auto s2 = "demo";
for (char s : s1) {...} //可以运行
for (char s : s2) {...} //不能运行。为什么?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值