博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ Primer 阅读笔记(一)
阅读量:3959 次
发布时间:2019-05-24

本文共 3866 字,大约阅读时间需要 12 分钟。

2.3 复合类型

2.3.1 引用

2.3.2 指针

1 指针

指向是指向另一种类型的复合类型

与引用类似

都实现了对其它对象的间接访问

与引用不同

指针本身是对象,允许对其赋值和拷贝

在其生命周期内,可以指向几个不同的对象

不需要在定义时赋初值,在块作用域若未初始化,则拥有一个不确定的值

2 获取对象的地址

指针存放某个对象的地址,获取对象地址,需用取地址符(&)

int val = 42;int *p = &val; // p指针存放变量val的地址,或者说p是指向val的指针

除了两种例外情况(后面总结),其它所有的类型都要和它所指向的对象严格匹配,若指针指向了一个其它类型的对象,则该对象操作将发生错误【编译不通过】在这里插入图片描述

3 指针值

指针的值 (即地址) 应属下列四种状态之一

1、指向一个对象

2、指向紧邻对象所占空间的下一位置

3、空指针,指针没有指向任何对象

4、无效指针,即上述情况之外的指针

拷贝或访问无效指针将引发错误,且编译器不会检查。这与使用未初始化的变量一样。第2,3种的指针有效,但没有指向任何对象,所以访问此类指针对象的行为不允许。

指向紧邻对象所占空间的下一位置如何理解?

例:声明一个 int32 数组,数组在初始化时会自动分配地址以及元素个数。假定起始地址为001E,int* p=arr,即指向该数组的指针,指向其首部001E。

按照位计算,4字节容量的int就是占有32位,即紧邻对象位置001E+32=003E再下一个位置就是003E+32=005E。一般不用按照占位运算,而是通过指针加减法,让编译器根据指针所指向的数据的大小进行移动

实际上就是通过指针算术运算,改变其指向的内存空间地址

4 利用指针访问对象

如果指针指向一个对象,则可用一个解引用符(*)来访问对象

对指针解引用会得到指向的对象,对解引用结果赋值就是给指向对象赋值

5 空指针

空指针不指向任何对象,在使用指针前需检查是否为空

几个生成空指针的方法

int *pl = nullptr;     // 等价于 int *pl = 0;int *p2 = 0;           //直接将p2初始化为字面常量0 需include cstdlibint *p3 = NULL;        // 等价于 int *p3 = 0;

nullptr 初始化指针是得到空指针最直接的方法,也是C++11新标准引入的办法。它是一种特殊的字面值,可以被转换成任意的指针类型,也可以通过字面值 0 来生成空指针

NULL是预处理变量,在头文件cstdlib中定义,它的值就是0。预处理变量不属于命名空间std,由预处理器管理,它会将预处理变量转换为实际值,因此用NULL初始 化指针和用0初始化指针是一样的

【建议】

在新标准下的C++程序最好使用nullptr,把 int (0) 变量直接赋给指针是错误操作

建议初始化所有指针,并且尽量定义对象后再定义指向它的指针。若不清楚指针指向何处,则初始化为nullptr或者0, 便于程序检测

6 赋值和指针

指针和引用都可以对其它对象的间接访问,而最重要的区别是,引用本身并非一个对象,无法绑定到另外对象上

指针没有这样的限制,给指针赋值就是令它存放一个新对象

确定改变指针值,还是所指对象值,只需:赋值改变的永远是等号左边的对象

7 其它指针操作

只要指针拥有一个合法值,就能用在表达式中,和采用算术值作为条件

int ival = 1024;int *pi = 0;                // pi合法,是一个空指针int *pi2 = &ival;           // pi2是一个合法的指针,存放着ival的地址 if (pi)                     // pi的值是0,条件的值是falseif (pi2)                    // pi2指向ival,值不是0,条件的值是true

任何非0指针对应的条件值都是true

对于两个类型相同的合法指针,可以用相等操作符(=)或不相等操作符(!=)来

比较,比较结果是布尔类型

如果两个指针存放地址值相同,则它们相等;反之不相等。两个指针相等有两种可能:它们都为空、 或都指向了同一地址

8 void*指针

void* 是一种特殊指针类型,可用于存放任意对象地址

一个 void* 指针存放着—个地址,但并不了解该地址中的对象类型

以 void 的视角看,内存空间仅仅是内存空间,无法访问内存空间中的对象

2.3.2 节练习

【练习 2.18】编写代码分别更改指针的值以及指针所指对象的值int a = 1 , b = 1;int *ptr = &a;*ptr = 2;  // 更改指针所指对象的值*ptr = &b; // 更改指针的值【练习 2.19】说明指针和引用的主要区别指针和引用类似都提供间接操作对象的方式,主要区别在于指针是对象而引用不是,因为指针不必初始化赋值,引用必须;指针可以拷贝赋值,引用不呢;指针生命周期内可以指向多个对象,引用只能和初始化的对象绑定;【练习2.20】请叙述下面这段代码的作用int i = 42;			// 用int字面值常量初始化变量iint *pl = &i; 		// 指针pl指向i,或把i的内存地址赋值给指针pl*pl = *pl * *pl;    // 为变量i赋值,值为 42*42【练习2.21】请解释下述定义。在这些定义中有非法的吗?如果有,为什么?int i = 0;(a) double* dp = &i; // 非法,除了两种特殊情况,指针类型和对象类型需一致  (b) int *ip = i;     // 非法,无法用整型的字面值常量给指针赋值(c) int *p = &i;     // 合法【练习2.22】假设p是一个int型指针,请说明下述代码的含义if (p) // 判断指针的值是否为0,即判断指针是否为空指针if (*p) // 判断指针指向的对象是否为0,判断指针指向对象值是否为0【练习2.23】给定指针p,你能知道它是否指向了一个合法的对象吗?如果能,叙述判断思路;如果不能,也请说明原因可以:用*p将其值输出,若编译器报错,证明p指向一个无效对象,要么p=0,要么p未进行初始化,此时可以用if(p == NULL)进行判断即可不可以:无法检测其实有效指针,且无法判断其指向的地址是否合法;【练习2.24】在下面这段代码中为什么p合法而lp非法?int i = 42;       void *p = &i; long *lp = &i;void* 指针为任意类型指针,可转换成任意指针类型;而lp为long类型指针,指针指向对象的类型必须和其类型一致

2.3.3 理解复合类型的声明

1 定义多个变量

变量定义 包括一个基本类型 + 声明符,在同一条定义语句中,基本类型只有一个,但声明符却不同。即,一 条定义语句可定义出不同类型变量

int i = 1024, *p = &i, &r = i;

基本数据类型是int而非int* , * 仅修饰了 p , 对声明语句中其它变量,不产生作用

int* p;            //合法但是容易产生误导

涉及指针或引用的声明,一般有两种写法

1、把修饰符和变量标识符写在一起

这种形式着重强调变量具有的复合类型

int *pl, *p2; // pl和p2都是指向int的指针

2、把修饰符和类型名写在一起,并且每条语 句只定义一个变量

这种形式着重强调声明定义了一种复合类型

int* pl;  // pl是指向int的指针int* p2;  // p2是指向int的指针

2 指向指针的指针

一般声明符中修饰符个数没有限制。当多个修饰符连写时,需按照其逻辑关系解释

以指针为例,指针是内存中的对象,像其它对象一样也有自己的地址,因此允许把指针的地址再存放到另一个指针当中

通过*的个数可以区分指针的级別。即,**表示指向指针的指针,***表示指向指针的指针的指针,以此类推int ival = 1024;int *pi = &ival; // pi 指向一个 int 型的数int **ppi = π // ppi指向一个 int 型的指针

3 指向指针的引用

引用不是对象,故不存在指向引用的指针,但指针是对象,所以存在指针的引用

int i = 42;int *p;         // p是一个int型指针int *&r = p;    // r是一个对指针p的引用r = &i;         // r引用了一个指针,因此给r賦值&i就是令p指向i *r = 0;

理解 r 类型,办法是从右向左阅读 r 定义

离变量名最近的符号决定变量类型,因此r是一个引用。声明符其余部分用以确定 r 引用的类型。* 说明 r 引用的是一个指针。基本数据类型部分指出 r 引用的是一个 int 指针

2.3.3节练习

【练习2.25】说明下列变量的类型和值(a) int* ip, i, &r = i;  // 指针(不确定) int整型(0) 引用(0)(b) int i, *ip = 0; 	 // int整型(0) 空指针(0)(c) int* ip, ip2;		 // 指针(不确定) int整型(0)

转载地址:http://bzozi.baihongyu.com/

你可能感兴趣的文章
杭电ACM——处理木棍(贪心)
查看>>
杭电ACM——broomstick训练营(贪心)
查看>>
杭电ACM——1018,Big Number(思维)
查看>>
杭电ACM——6463(思维)
查看>>
杭电AC——6561(思维)
查看>>
杭电ACM——1034,Candy Sharing Game
查看>>
杭电ACM——建房子(贪心)
查看>>
杭电ACM——1297,Children’s Queue(递推)
查看>>
杭电ACM——1003,Max Sum(DP)
查看>>
杭电ACM——1042,N!(思维)
查看>>
杭电ACM——1060,Leftmost Digit(思维)
查看>>
杭电ACM——1061,Rightmost Digit(思维)
查看>>
杭电ACM——1087,Super Jumping! Jumping! Jumping!(DP)
查看>>
杭电ACM——fatmouse's speed(DP)
查看>>
杭电ACM——毛毛虫(DP)
查看>>
杭电ACM——humble numbers(DP)
查看>>
杭电ACM——6467,简单数学题(思维)
查看>>
杭电ACM——天上掉馅饼(DP)
查看>>
杭电ACM——1086,You can Solve a Geometry Problem too(思维)
查看>>
杭电ACM——2057,A + B Again(思维)
查看>>