前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第2章 变量和基本类型

第2章 变量和基本类型

作者头像
用户1653704
发布2018-06-07 14:12:51
6450
发布2018-06-07 14:12:51
举报

1.位、字节、字、KB

位(bit),电子计算机中最小的数据单位。每一位的状态只能是0或1。

字节(byte),可寻址的最小内存块,存储的基本单元,1byte=8bit。

字(word),进行数据处理和运算的单位,不同机器其字长不同。32位机器上,1字=4字节=32位;64位机器上,1字=8字节=64位。

1KB = 1024B(字节)

1个char型数据占8位,1个字节。1个英文字母占1字节,1个汉字占2个字节。

表示范围。 若数据类型 F占 n位,则无符号类型:0~2n-1,带符号类型:-2n-1~2n-1-1。

2.建议,使用 int执行整数运算,double执行浮点数运算。

3.给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值的总个数取模后的余数。如下例所示

代码语言:javascript
复制
1 unsigned char c = -1;  // c值实际上为255
2 unsigned char d = 257;  // d实际上值为 1
代码语言:javascript
复制
注意,取模(mod)和取余(rem)运算是有区别的。取模,是向小指(负无穷)取值;取余,是向0取值。当被操作数是负数时,二者是不一样的。

-1(mod)256 = -1 + 255; -1(rem)256 = 0 + (-1);

4.不要滥用无符号类型,看下面两个例子。

1)死循环。

代码语言:javascript
复制
1 for (unsigned u = 10; u >= 0; --u)
2     do sth;

这里,当u=0且执行--u时,由于u是无符号类型,此时u=232-1,而不是-1。这样,整个程序就会是个死循环。

2)对无符号数和带符号数进行运算,此时带符号数会自动转换为无符号数。

代码语言:javascript
复制
1 int i = 10;
2 unsigned u = 42;
3 // 预想的输出为 -32,可实际输出为 -32+2^32,4294967264
4 cout << i - u << endl;

5.八进制和十六进制字面值的类型,是能容纳其数值的类型中的尺寸最小者。浮点型字面值默认为 double。

6.两个字符串字面值位置紧邻且仅由空格、缩进和换行符分隔,则实际上是一个整体。下面写在多行的字符串整体实际上是一个字面值。

代码语言:javascript
复制
1 // 分多行书写的字符串字面值
2 cout << "a really, really long string literal "
3               "that spans to two lines" << endl;

7.转义字符,以反斜线开始,如 \n \t \' \'' \\等。比较有意思的是 \a,报警符,会发出 bi声。另外,还可以使用泛化的转义序列,\后不多于3个八进制数字,\x后1个十六进制数字。\n = \12 = \xa,这3个都是换行符。

8.一行语句可以定义多个变量,并为其中某些变量赋初值。可以这么理解,它们彼此独立,只是共同遵循同一个类型说明符。

代码语言:javascript
复制
1 int sum = 0, value, units_sold = 0;

9.C++中,初始化和赋值并不相同。初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来代替。要知道,在初始化时,变量刚刚创建,此时是没有当前值可供擦除的。

10.变量初始化,下面4条语句都可以完成。

代码语言:javascript
复制
1 int a = 0;
2 int a = {0};
3 int a{0};
4 int a(0);

其中,第2和3种方法使用了花括号{},这种方式称为列表初始化。在C++11新标准中,这种方法得到了广泛的应用。它的一个重要特点是:初始值存在丢失信息的风险,编译器将报错。如下所示

代码语言:javascript
复制
1 double d = 3.14;
2 int a{d}, b = {d};   // 错误,存在精度丢失
3 int c(d), e = d;     // 正确,类型转换,但也丢失了精度

不过,在进行类内数据成员初始化时,不能使用 '()',其他三种方式都可以。

11.定义变量时未初始化,则执行默认初始化。

1)定义在函数体外的变量将会被初始化为 0。

2)定义在函数体内部的变量将不会被初始化,其值未定义。

3)类的对象未被初始化,其值由类决定。

12.分离式编译机制下,程序可以被分割为多个文件。为了在文件间共享变量,将声明和定义分离开来。一次定义,多次声明和使用。使用 extern关键字,不进行显示地初始化。

代码语言:javascript
复制
1 extern int i;         // 声明而非定义 i
2 extern int j = 1;  // 定义

13.C++中,不允许在函数外对全局变量赋值,全局变量只能在定义的时候进行初始化。下面的式子就是错误的。

代码语言:javascript
复制
int ta;
ta = 1;

另外,在块作用域内访问全局作用域内的同名变量,可以使用域操作符 "::"来实现。

代码语言:javascript
复制
 1 #include <iostream>
 2 using namespace std;
 3 // 该程序仅用于说明,函数内部不宜定义与全局变量同名的新变量
 4 int a = 42;              // 全局变量,全局作用域
 5 void main()
 6 {
 7    int a = 10;           // 局部变量,块作用域
 8    cout << a << '\n';    // 输出 10 
 9    cout << ::a << '\n';  // 输出 42  
10 }

14.引用

1)引用是与初始值绑定到一起,而不是将初始值拷贝给引用。

2)引用无法重新绑定,一直与初始对象绑定到一起,因此必须初始化。

3)引用不是对象,只是已存在对象的别名,不能定义引用的引用。以引用作为初始值,实际上是以与引用绑定的对象作为初始值。

4)非常量引用不能与字面值或表达式绑定到一起。

15.指针

1)指针本身是一个对象,允许赋值和拷贝,而且在生命周期内可以先后指向不同的对象。

2)无须在定义时赋初值。在块作用域定义时,如果未初始化,其值将不确定。

3)引用不是对象,没有实际地址,不能定义指向引用的指针。

16.C++11中,最好用 nullptr来初始化空指针。不能把 int变量直接赋给指针,下面的代码是错误的。

代码语言:javascript
复制
1 int zero = 0;
2 int *p = zero;  // 错误!

17.void*指针,可以存放任意类型的指针,不过没办法访问内存空间中所存的对象。想要获取其内容,可以使用强制类型转换。

代码语言:javascript
复制
1 int a = 1;
2 void *pi = &a;
3 cout << *pi << '\n';    // 报错,不能取出其值
4 int *pa = static_cast<int *>(pi);
5 cout << *pa << '\n';   // 成功输出 1

18.指向指针的引用

代码语言:javascript
复制
1 int i = 1;
2 int *pi = &i;
3 int *&ri = p;  // 对指针 p的引用

可以这么来理解

  1)将 &ri看作是一个整体 pp,则变成 int *pp = p; 可以看到 pp是个 int型指针,指向 p所指向的内容。

  2)&ri是一个 int型指针,即 ri是 int型指针的引用。

19.const限定符

1)const对象一旦创建后其值不能再改变,所以必须进行初始化。但是不区分是编译还是运行时初始化。

2)利用一个对象去初始化另一个对象,它们是不是 const都无关紧要,如

代码语言:javascript
复制
1 int i=42;
2 const int ci = i;  // 正确,值拷贝
3 int j = ci;           // 正确,值拷贝

3)默认状态下,const对象仅在文件内有效。要想在多个文件内使用同一个 const对象,添加 extern关键字,

代码语言:javascript
复制
1 // file_1.h文件,定义并初始化
2 extern const int bufSize = 512;
3 // file_2.h文件,声明该常量
4 extern const int bufSize;

这样的变量具有三个特点。1.能被外部文件访问。2.只定义一次。3.不可改变。

4)对 const的引用。

    4-1.允许为一个常量引用绑定非常量的对象、字面值,甚至是一个一般表达式,而类型也没有硬性要求,只要能成功类型转换即可。而普通引用则不可以引用 字面值和表达式,类型也必须一致。

代码语言:javascript
复制
int i = 42;
const int &r1 = i;              // 正确
const int &r2 = 42;             // 正确
const int &r3 = r1 * 2;         // 正确
int &r4 = i;                    // 正确
int &r5 = r1;                   // 错误,普通的 int不能绑定到 int常量
int &r6 = 42;                   // 错误
double j = 1.0;
int &r7 = j;                    // 错误
const int &r8 = j;              // 正确

4-2.对 const的引用可以引用一个非 const对象,只是说不能通过该引用去修改所绑定的对象,并不影响该对象通过其他方式进行改变。

5)指针和 const

    5-1.三种常见的指针和const的组合如下所示,在分析时,可以遵循就近原则来判断语义。

代码语言:javascript
复制
1 const int *p;        // 指向常量的指针,底层const
2 int *const p = &pi;  // 指针本身为常量,顶层const,必须进行初始化
3 const int *const p = &pi;  // 指向常量的常量指针,靠左是底层const,靠右是顶层const,也必须进行初始化

5-2.执行拷贝操作,顶层const没有影响,拷入和拷出的对象是否是常量都没什么影响。然而底层const的限制却不能忽略,非常量可以转化成常量,反之则不行。

    5-3.常量表达式,不改变,且编译时就知道结果。C++11新标准中,将常量表达式声明成 constexpr类型,编译器将会验证该变量是否是一个常量表达式。

20.类型别名,使复杂的类型名字变得简单明了、易于理解,下面两种方法都可以

代码语言:javascript
复制
1 typedef double wages, *p;  // wages是double的同义词,p是double*的同义词
2 using SI = Sales_item;      // SI是Sales_item的同义词

注意,如果类型别名是符合类型或常量时,在剖分语义时,不能把类型别名替换成原来的样子,而是将类型别名整体看成一个基本数据类型。可以将 pstring当做是 int一样的基本类型,先解释外面的部分,最后再来解释 pstring本身。如下

代码语言:javascript
复制
1 typedef char *pstring;
2 const pstring cstr = 0;   // cstr是指向 char的常量指针
3 const pstring *ps;        // ps是一个指针,对象是指向 char的常量指针
4 // 第2行代码的两种解释方案
5 const (char) * cstr;      // 错误,基本类型为 char,解释成指向 const char的指针
6 const (char*) cstr;       // 正确,基本类型为char*,解释成指向 char的常量指针

21.auto类型说明符,编译器替我们去分析表达式所属的类型,必须有初始值。

1)一条语句也可以声明多个变量,但所有变量的初始基本数据类型应该是一样的,因为一条声明语句只能有一个基本类型。比如

代码语言:javascript
复制
1 auto i = 0, *p = &i;     // 正确
2 auto sz = 0, pi = 3.14;  // 错误,sz和 pi的类型不一致

2)编译器在进行 auto类型推断时,其值和初始值的类型并不完全一样。

       ①引用作为初始值时,真正参与初始化的是引用的值。

       ②auto一般会忽略顶层 const,底层 const则会保留下来。

       ③如果希望推断出的 auto类型是一个顶层 const,则需要显示加上 const修饰符。

       ④设置 auto类型为引用时,初始值中的顶层 const仍然保留。

代码语言:javascript
复制
1 int i = 0;
2 const int ci = i, &cr = ci;
3 auto b = ci;         // b是整数
4 auto c = cr;         // c是整数
5 auto e = &ci;        // e是指向整数常量的指针
6 const auto f = ci;   // ci的推演类型是 int,f是 const int
7 auto &g = ci;        // g是一个整型常量的引用
8 auto &h = 42;        // 错误,不能为非常量引用绑定字面值
9 const auto &j = 42;  // 正确 

22.decltype类型指示符,只希望推断出要定义的变量的类型,而不想用该表达式的值初始化变量。它与 auto在类型推断上有所不同,

      1)decltype会将顶层 const和引用包括在内,返回该变量的类型。

       2)当表达式可作为左值或被加上了一层或多层括号,反回的是相应类型的引用。不过加括号貌似只对变量有影响,对于表达式好像没有影响。

代码语言:javascript
复制
 1 const int ci = 0, &cj = ci;
 2 decltype(ci) x = 0;    // x的类型是 const int
 3 decltype(cj) y = x;    // y的类型是 const int&,必须初始化
 4 int i = 42, *p = &i, &r = i;
 5 decltype(i) a;         // a是 int
 6 decltype((i)) b = i;   // b是 int&,必须初始化
 7 decltype(r) c = i;     // c是 int&,必须初始化
 8 decltype(r+0) d;       // d是 int
 9 decltype((r+0)) e;     // e是 int
10 decltype(*p) f = i;    // f是 int&,必须初始化

23.C++11新标准规定,可以为类内的数据成员提供一个类内初始值。赋值时,不能使用圆括号,建议使用花括号。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-10-30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档