C++ Primer 学习 -- Day 1

第 1、2 章知识点总结

  • 1、Hello,World!
    • 1.1、输入输出
    • 1.2、while(std::cin >> value)
  • 2、变量和基本类型
    • 2.1.1、unsigned
      • ==建议==
    • 2.1.2 类型转换
      • ==建议==
      • ==建议==
    • 2.2.1 变量定义
      • ==提醒==
      • 列表初始化
      • ==提醒==
    • 2.2.2 变量声明和定义
      • ==提醒==
    • 2.3.1 引用
      • 引用特点
    • 2.3.2 指针
      • 指针特点
      • ==关键概念==
      • ==建议==
      • ==建议==
      • void * 指针
    • 2.3.3 理解复合类型的声明
      • ==提醒==
      • 指向指针的引用
    • 2.4.0 const 限定符
      • 特点:
      • ==提醒==
      • ==笔记==
    • 2.4.1 const 引用
      • 特点
    • 2.4.2 指针和const
      • 特点:
      • ==题目==
    • 2.4.3 顶层 const
    • 2.4.4 constexpr 和常量表达式
      • 常量表达式
      • constexpr 变量
      • 字面值类型
      • 指针和 constexpr
    • 2.5.1 类型别名
    • 2.5.2 auto 类型说明符
    • 2.5.3 decltype 类型指示符
      • ==注意==
      • ==提醒==
      • decltype 和引用
      • ==题目==
    • 2.6

1、Hello,World!

1.1、输入输出

#include      //引入库
using namespace std;    //使用名字为 std 的命名空间
int main(){
   
    int x, y;
    std::cin >> x >> y;
    std::cout << x << std::endl;    //是字母l不是数字1哦
}

① 前缀 std:: 指出名字 cin 和 cout 是定义在名为 std 的命名空间(namespace)中的。命名空间可以帮助我们避免不经意的名字定义冲突,以及使用库中相同名字导致的冲突。标准库定义的所有名字都在命名空间 std 中。

② 输出语句中的 endl 的效果为:结束当前行,并将与设备关联的缓冲区(buffer)中的内容刷到设备中。此缓冲刷新操作可以保证到目前为止程序所产生的所有输出都真正写入输出流中,而不是仅停留在内存中等待写入流。所有在调试中使用cout 语句测试时 + “<< std::endl” 不容易出错

所得:规范书写很重要,不要觉得麻烦,省略了好像也没事就不写

1.2、while(std::cin >> value)

​ 当我们使用一个 istream 对象作为条件的时候,其效果是检测流的状态。如果流是有效的,即流未遇到错误,那么检测成功。当遇到文件结束符(end-of-file),或遇到一个无效输入时(如定义value为 int 类型,cin输入的值不是整数,istream对象的状态就会变为无效。处于无效状态的 istream 对象会使条件变为假。

2、变量和基本类型

2.1.1、unsigned

​ 一般int、short、long 和long long 都是带符号的,通过在这些类型名前添加unsigned 就可以得到无符号类型(不能取负值,但是能表示的正数值域翻倍)

建议

① 当明确知晓数值不可能为负时,选用无符号类型。

② 在算术表达式中不要使用char 或 bool ,只有存放字符或布尔值时才使用它们。因为类型char 在一些机器上有符号的,在另一些机器上是无符号的,所以使用char 进行运算特别容易出问题。

③ 执行浮点数运算选用 double,精度更高,运算更快。

2.1.2 类型转换

① 把一个非布尔型的算术值赋给布尔类型时,初始值为0 则结果为 false,否则结果为 true。

② 当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。

③ 当我们赋给带符号类型一个超出它表示范围的值时,结果是未定义的(undefined)。此时,程序可能工作、可能崩溃、可能生成垃圾数据。

bool b = 42;                         // b 为 true;
unsigned char c = -1;                // 假设char 占8 比特,c 的值为 255
signed char c2 = 256;                // 假设char 占8 比特,c 的值是未定义的

建议

避免无法预知和依赖于实现环境的行为

① 无法预知的行为源于编译器无须(有时是不能)检测的错误。即使代码编译通过了,如果程序执行了一条未定义的表达式,仍可能产生错误。

② 程序也应该尽量避免依赖于实现环境的行为。如果我们把 int 的尺寸看成是一个确定不变的已知值,那么这样的程序就称作不可移植的(nonportable)。当程序移植到别的机器上后,依赖于实现环境的程序可能就会发生错误。

建议

切勿混用带符号类型和无符号类型

​ 如果表达式里既带有符号类型又有无符号类型,当带符号类型取值为负时会出现异常结果,这是因为带符号数会自动转换成无符号数。

unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl;    // 输出 -84
std::cout << u + i << std::endl;    // 如果 int 占 32 位,输出 4294967264

// 注意,无符号的 for 循环问题
// 错误:变量 u 永远也不会小于 0 ,循环条件一直成立
for (unsigned u = 10; u >= 0; --u) 
    std::cout << u << std::endl;     //当 u == 0 时,执行 --u 会成正数

// 解决方法其一
unsigned u = 10;
while (u > 0) {
       
    --u;                    //先减 1 ,这样最后一次迭代时就会输出 0     
    std::cout << u << std::endl;
}

2.2.1 变量定义

对象:一块能存储数据并具有某种类型的内存空间

提醒

初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来代替。

列表初始化

// 以下 4 条语句都可以 定义一个名为 units_sold 的 int 变量并初始化为 0
int units_sold = 0;
int units_sold = {
   0}; 
int units_sold{
   0};
int units_sold(0);

// 注意:如果我们使用列表初始化且初始值存在丢失信息的风险,则编译器将报错:
long double ld = 3.1415925536;
int a{
   ld}, b = {
   ld};      // 错误:转换未执行,因为存在丢失信息的风险
int c(ld), d = ld;        // 正确:转换执行,且确实丢失了部分值

提醒

建议初始化每个内置类型的变量。虽然并非必须这么做,但如果我们不能确保初始化后程序安全,那么这么做不失为一种简单可靠的方法

2.2.2 变量声明和定义

​ C++ 语言支持**分离式编译(separate compilation)**机制,该机制允许将程序分割为若干个文件,每个文件可被独立编译。

​ 为了支持分离式编译,C++ 语音将声明和定义区分开来。**声明(declaration)使得名字为程序所知,而定义(definition)**负责创建与名字关联的实体。

// 如果想声明一个变量而非定义它,就在变量名前添加关键字 extern,而且不要显式地初始化变量:
extern int i;    // 声明 i 而非定义 i
int j;           // 声明并定义 j

// 注意:如果我们由 extern 关键字标记的变量赋一个初始值,就抵消了 extern 的作用,变成了定义
extern double pi = 3.1416;   // 定义

变量能且只能被定义一次,但是可以被多次声明。

提醒

当你第一次使用变量时再定义它

​ 一般来说,在对象第一次被使用的地方附近定义它是一种好的选择,因为这样做有助于更容易地找到变量的定义。更重要的是,当变量的定义与它第一次被使用的地方很近时,我们也会赋给它一个比较合理的初始值。

2.3.1 引用

**引用(reference)**为对象起了另外一个名字,引用类型引用(refers to)另外一种类型。通过将声明符写成 &d 的形式来定义引用类型,其中 d 是声明的变量名。

int ival = 1024;
int &refVal = ival;                  // refVal 指向 ival (是 ival 的另一个名字)
int &refVal2;                        // 报错:引用必须被初始化

引用特点

① 引用必须初始化。一般在初始化变量时,初始值会被拷贝到新建的对象中。然而定义引用时,程序把引用和它的初始值**绑定(bind)**在一起,而不是将初始值拷贝给引用。一旦绑定在一起后就无法再绑定其他对象了。

你可能感兴趣的:(C++,Primer,c++,学习,开发语言,笔记)