当前课程知识点:基于Linux的C++ >  第七讲 指针与引用 >  7.4 指针与复合数据类型(一) >  LinuxCPP0704

返回《基于Linux的C++》慕课在线视频课程列表

LinuxCPP0704在线视频

LinuxCPP0704

下一节:LinuxCPP0705

返回《基于Linux的C++》慕课在线视频列表

LinuxCPP0704课程教案、知识点、字幕

接下来就是指针和复合数据类型的关系

我们先看指针和数组的关系

这里边涉及到几个地方

第一个 数据对象的地址该怎么去计算

第二个 作为函数参数的指针和数组

它们之间相同的地方和不同的地方

很多情况下边 指针和数组是可互换的

多维数组作为函数参数的时候

怎么去处理它

接下来就是指针和结构体

指针指向一个结构体怎么弄

指针就是结构体的一个成员

该怎么去处理指针和结构体之间的关系

我们先看指针和数组之间的关系

回忆我们介绍数组的时候谈到过的

数据对象地址的计算

我们原来有一个数组定义int a[8]

数组的基地址就是&a或者写a

因为我们当时说过 这个数组元素

它的存储顺序就是0号元、1号元、2号元

它就按照这个顺序放

前面没有任何控制格式的存储空间

后续也没有结束标记

数组的基地址就是

数组的0号元的基地址

所以你写&a[0]

取的就是数组的0号元的基地址

当然就是数组的基地址

我想知道这个数组的

第i号元的基地址怎么办呢

因为它紧挨着存放的

所以就用0号元的基地址加上i * sizeof(int)

就能够算出它的第i号元的基地址

因为每一个元素都是一个整数

每一个整数占的存储空间的大小是sizeof(int)

乘上i(第几号元)

就得到了第几号元的基地址

这就是标准的计算的式子

因为我们前面讲了真实表达地址的时候

&a[0]它其实就是和a是等价的

表达它的地址概念的时候

数组第i号元的基地址就是a + sizeof(int)

定义了这个int a[8] 我用个指针int *p

p赋值为0号元的基地址

p将指向我们的0号元

如果你还有一个指针q

让q赋值为&a[2] 让q指向2号元

现在怎么能够表达这两个指针

p、q之间的联系呢

p、q这两个指针

两个彼此之间一点关系都没有

它明明是指向一个数组中的两个元素啊

它们怎么能够一点关系都没有呢

它们都指向同一个数组中的元素

怎么表达这两者之间的关系

这个就涉及到了指针的算术运算

指针可以和一个整数进行一种加减运算

如果我设p为指向数组中的

某一个元素的指针 i为整数

p+i就表示这个指针

向后滑动i个整数单位

p-i就表示指针向前滑动i个单位

p如果一开始指向a[0]的

p+2就会指向a[2]

p如果一开始指向a[3]的

p-2就会指向a[1]

加2就是向后滑动两个单位

就向数组的尾部滑动两个元素

元素的类型是什么 就滑动多少

整数数组 那就滑动两个整数

如果是一个指向结构体的数组

那么每个元素都是一个结构体

那就滑动i个结构体

因为我们这里面是整数

所以滑动i个整数

不是滑动多少个字节数

你如果这么说 p是指向a[0]的

一开始q是指向a[2]的

p+2就是指向a[2]的

所以q如果赋值为p+2

那么q就会指向a[2]

注意这个式子

这是一个赋值表达式

指针和整数加减运算的时候

它是以一个指针

所指向目标数据对象为单位的

不是以字节为单位的

还有一种情况就是加加减减操作符

我们的递增递减运算

指针允许你做递增递减运算

如果p是指向a[0]的

那么p++就会指向a[1]

如果p是指向a[1]的

那么--p就会指向a[0]

回到我们刚才例子 Q赋值为p+2

q会指向a[2]

p+2也会指向a[2]

这就意味着这两个指针指向同一个地方

就意味着这两个指针的值

本身是相等的 在数学上是相等的

所以你一改 把p挪到等式的左边

你一下就看到 这就是q-p结果就是2

这个就是指针的减法运算

你可以对两个指针进行一个

标准的减法运算

减法的结果就是一个整数

它表示这两个指针

它们中间间隔的元素个数

它是连头不连尾 或者连尾不连头

也就是说两边的数据你不能都算

p是指向0号元 q指向2号元

所以q-p结果就是2

如果我用一个指针

指向一个数组的0号元

我还有一个指针

指向这个元素的最后一个

这两者差值就是数组的元素个数减一

减一这个过程很讨厌

就可以弄一个招

我在这个数组最后

专门设计一个过尾的元素

让p指向数组的0号元

让q指向这个数组的

最后一个元素后边的位置

所以这两者一减

就正好是数组的元素个数

最后那个元素就叫过尾元

指针还可以进行关系运算

我可以判定两个指针是不是相等

也就说是不是指向同一个地方

p==q、p!=q 这样判断都是可以的

还有一种很特殊的东西

它是一个空指针

有一个定义的宏 叫NULL

它表示空指针 指针值就是0

表示这个指针不指向任何一个地方

就用NULL来表示它

其实它指向的是内存条最开头的存储区

不过现在主流的操作系统下边

几乎所有的操作系统在那个存储区

都是什么数据都不保存的

专门就用来捕获我们的指针错误的

所以如果p赋值为NULL

就表示p不指向任何有意义的

目标数据对象 有了它

就可以测试指针p是不是有意义的

如果我在写程序的过程中

我保证了这个指针p

要么是指向一个合法有效的数据对象

要么就是指向0

每次使用指针之前

就可以通过这个测试if(p != NULL)

来测试这个指针是不是有效的

这样的话 p != NULL说明它是有效的

p == NULL 说明它是无效的

如果你不测试这个指针是不是有意义的

当你在编写带有指针的程序的时候

它非常容易出错

如果这个指针是错的

它指向一个无意义的地方

或者它没有权力去访问的地方

这个程序不是错的 而是崩溃

这个错误就太严重了

所以我们每次使用指针

就需要特别注意这一条

每次访问指针

想通过引领操作符

访问它的目标数据对象的时候

都要测试这个指针是不是有意义的

指针数据对象 理论上来讲

你应该对它进行初始化

要么是合法有效的

目标数据对象的地址 要么就是0

只有这样才能够保证你的测试

每次都是有意义的

因为如果你不对它进行初始化

它是个全局量 自动被初始化为0

如果这个指针变量本身是个局部量

那么它内部的位序列就是随机的

极有可能不是0

如果不是0 你一访问

目标数据对象区域没有权力访问的

程序一下就崩了

当作为函数参数的时候

指针和数组具有什么样的关系

我们先来回忆数组作为函数参数的时候

我们当时是怎么用的

我们当时函数定义是按照这个格式:

void GenerateIntegers( int a[], unsigned int n)

我们是按照这个方式写的

第一个参数要传这个数组

第二个参数要传数组的元素个数

我们那时候讲

如果你直接在这个数组中括号里面

写元素个数 写一个魔数进去

当时我们说那个不好

你不写也不成

所以我们就真不写

但是后边传一个额外的第二个参数

把元素个数给传进去

就按照这个方式去写的

到这个函数内部可以写一个for循环

然后a[i]一个一个去操作

我们当时讲了 数组作为函数参数

是能够带回来结果的

用的时候就会定义像这样的数组:

int a[NUM_OF_ELEMENTS]

NUM_OF_ELEMENTS

就是我们定义的一个宏 值是8

然后我们调用这个函数GenerateIntegers

第一个参数传数组的基地址

第二个参数传数组的元素个数

这就是数组作为函数参数的时候

我们当时是这么定义 这么使用的

现在如果我们使用指针

作为函数的参数

那么我们应该这么写:int *p

这是指向整数的一个指针

第二个参数同样地要传元素的个数

我们内部去访问它

就使用*p(引领操作符)

来访问它所指向的数组0号元

i从0开始 p一开始传数组基地址进来

它指向的就是数组的0号元

*p一操作 一赋值

那么就会把0号元给设了值

然后我用指针运算p++

让它指向1号元

看这段代码 写的是*p++

这是两个操作符*p、p++

因为是后缀++

所以要把GenerateRandomNumber函数调用以后

生成的那个整数赋值给*p

然后才能做p++

它做的绝不是(*p)++,不是(*p)

如果你是想把*p的目标量累加

那么你必须写(*p) 括号完毕之后++ 那才对

p一开始指向0号元

所以把生成的那个数赋值给0号元

然后p++ 让p指向1号元

循环第二次迭代

赋值 p指向2号元

它是按照这个方式

不断去操纵这个数组的每个元素的

这是指针作为函数参数

在实际调用的时候

它和数组作为函数参数没什么差别

同样定义是一个数组

int a[NUM_OF_ELEMENTS]

同样地调用GenerateIntegers

传数组的基地址 传数组的元素个数

实际使用的时候

传递的和刚才是一模一样的

但是你要记住

你要传已经分配空间的数组的基地址

你不能传其它的指针(没有分配空间的)

我们这里边传递int a[NUM_OF_ELEMENTS]

这个数组的空间

在调用之前就分配好了的

把它基地址传进去

基于Linux的C++课程列表:

第一讲 C/C++基本语法元素

-1.1 提纲

--LinuxCPP0101

-1.2 程序设计的基本概念

--LinuxCPP0102

-1.3 简单C/C++程序介绍

--LinuxCPP0103

-1.4 程序设计的基本流程

--LinuxCPP0104

-1.5 基本语法元素

--LinuxCPP0105

-1.6 程序设计风格

--LinuxCPP0106

-1.7 编程实践

--LinuxCPP0107

-第一讲 C/C++基本语法元素--编程实践提交入口

第二讲 程序控制结构

-2.1 提纲

--LinuxCPP0201

-2.2 结构化程序设计基础

--LinuxCPP0202

-2.3 布尔数据

--LinuxCPP0203

-2.4 分支结构

--LinuxCPP0204

-2.5 break语句

--LinuxCPP0205

-2.6 循环结构

--LinuxCPP0206

-2.7 编程实践

--LinuxCPP0207

-第二讲 程序控制结构--编程实践提交入口

第三讲 函数

-3.1 提纲

--LinuxCPP0301

-3.2 函数声明、调用与定义

--LinuxCPP0302

-3.3 函数调用栈框架

--LinuxCPP0303

-3.4 编程实践

--LinuxCPP0304

-第三讲 函数--编程实践提交入口

第四讲 算法

-4.1 提纲

--LinuxCPP0401

-4.2 算法概念与特征

--LinuxCPP0402

-4.3 算法描述

--LinuxCPP0403

-4.4 算法设计与实现

--LinuxCPP0404

-4.5 递归算法(一)

--LinuxCPP0405

-4.6 递归算法(二)

--LinuxCPP0406

-4.7 容错与计算复杂度

--LinuxCPP0407

-4.8 编程实践

--LinuxCPP0408

-第四讲 算法--编程实践提交入口

第五讲 程序组织与开发方法

-5.1 提纲

--LinuxCPP0501

-5.2 库与接口

--LinuxCPP0502

-5.3 随机数库(一)

--LinuxCPP0503

-5.4 随机数库(二)

--LinuxCPP0504

-5.5 作用域与生存期

--LinuxCPP0505

-5.6 典型软件开发流程(一)

--LinuxCPP0506

-5.7 典型软件开发流程(二)

--LinuxCPP0507

-5.8 编程实践

--LinuxCPP0508

-第五讲 程序组织与开发方法--编程实践提交入口

第六讲 复合数据类型

-6.1 提纲

--LinuxCPP0601

-6.2 字符

--LinuxCPP0602

-6.3 数组(一)

--LinuxCPP0603

-6.4 数组(二)

--LinuxCPP0604

-6.5 结构体

--LinuxCPP0605

-6.6 编程实践

--LinuxCPP0606

-第六讲 复合数据类型--编程实践提交入口

第七讲 指针与引用

-7.1 提纲

--LinuxCPP0701

-7.2 指针基本概念

--LinuxCPP0702

-7.3 指针与函数

--LinuxCPP0703

-7.4 指针与复合数据类型(一)

--LinuxCPP0704

-7.5 指针与复合数据类型(二)

--LinuxCPP0705

-7.6 字符串

--LinuxCPP0706

-7.7 动态存储管理(一)

--LinuxCPP0707

-7.8 动态存储管理(二)

--LinuxCPP0708

-7.9 引用

--LinuxCPP0709

-7.10 编程实践

--LinuxCPP0710

-第七讲 指针与引用--编程实践提交入口

第八讲 链表与程序抽象

-8.1 提纲

--LinuxCPP0801

-8.2 数据抽象(一)

--LinuxCPP0802

-8.3 数据抽象(二)

--LinuxCPP0803

-8.4 链表(一)

--LinuxCPP0804

-8.5 链表(二)

--LinuxCPP0805

-8.6 链表(三)

--LinuxCPP0806

-8.7 链表(四)

--LinuxCPP0807

-8.8 函数指针(一)

--LinuxCPP0808

-8.9 函数指针(二)

--LinuxCPP0809

-8.10 抽象链表(一)

--LinuxCPP0810

-8.11 抽象链表(二)

--LinuxCPP0811

-8.12 编程实践

--LinuxCPP0812

-第八讲 链表与程序抽象--编程实践提交入口

第九讲 类与对象

-9.1 提纲

--LinuxCPP0901

-9.2 程序抽象与面向对象

--LinuxCPP0902

-9.3 类类型

--LinuxCPP0903

-9.4 对象(一)

--LinuxCPP0904

-9.5 对象(二)

--LinuxCPP0905

-9.6 类与对象的成员(一)

--LinuxCPP0906

-9.7 类与对象的成员(二)

--LinuxCPP0907

-9.8 类与对象的成员(三)

--LinuxCPP0908

-9.9 继承(一)

--LinuxCPP0909

-9.10 继承(二)

--LinuxCPP0910

-9.11 继承(三)

--LinuxCPP0911

-9.12 多态(一)

--LinuxCPP0912

-9.13 多态(二)

--LinuxCPP0913

-9.14 编程实践

--LinuxCPP0914

-第九讲 类与对象--编程实践提交入口

第十讲 操作符重载

-10.1 提纲

--LinuxCPP1001

-10.2 四则运算符重载(一)

--LinuxCPP1002

-10.3 四则运算符重载(二)

--LinuxCPP1003

-10.4 关系与下标操作符重载

--LinuxCPP1004

-10.5 赋值操作符重载(一)

--LinuxCPP1005

-10.6 赋值操作符重载(二)

--LinuxCPP1006

-10.7 赋值操作符重载(三)

--LinuxCPP1007

-10.8 赋值操作符重载(四)

--LinuxCPP1008

-10.9 赋值操作符重载(五)

--LinuxCPP1009

-10.10 流操作符重载(一)

--LinuxCPP1010

-10.11 流操作符重载(二)

--LinuxCPP1011

-10.12 流操作符重载(三)

--LinuxCPP1012

-10.13 操作符重载总结

--LinuxCPP1013

-10.14 编程实践

--LinuxCPP1014

-第十讲 操作符重载--编程实践提交入口

第十一讲 泛型编程

-11.1 提纲

--LinuxCPP1101

-11.2 泛型编程概览

--LinuxCPP1102

-11.3 异常处理机制(一)

--LinuxCPP1103

-11.4 异常处理机制(二)

--LinuxCPP1104

-11.5 运行期型式信息(一)

--LinuxCPP1105

-11.6 运行期型式信息(二)

--LinuxCPP1106

-11.7 模板与型式参数化

--LinuxCPP1107

-11.8 题外话:术语翻译

--LinuxCPP1108

-11.9 泛型编程实践(一)

--LinuxCPP1109

-11.10 泛型编程实践(二)

--LinuxCPP1110

-11.11 泛型编程实践(三)

--LinuxCPP1111

-11.12 泛型编程实践(四)

--LinuxCPP1112

-11.13 泛型编程实践(五)

--LinuxCPP1113

-11.14 泛型编程实践(六)

--LinuxCPP1114

-11.15 泛型编程实践(七)

--LinuxCPP1115

-11.16 泛型编程实践(八)

--LinuxCPP1116

-11.17 泛型编程实践(九)

--LinuxCPP1117

-11.18 泛型编程实践(十)

--LinuxCPP1118

-11.19 编程实践

--LinuxCPP1119

-第十一讲 泛型编程--编程实践提交入口

第十二讲 Linux系统编程基础

-12.1 提纲

--LinuxCPP1201

-12.2 程序执行环境(一)

--LinuxCPP1202

-12.3 程序执行环境(二)

--LinuxCPP1203

-12.4 程序执行环境(三)

--LinuxCPP1204

-12.5 程序执行环境(四)

--LinuxCPP1205

-12.6 输入输出(一)

--LinuxCPP1206

-12.7 输入输出(二)

--LinuxCPP1207

-12.8 文件系统

--LinuxCPP1208

-12.9 设备

--LinuxCPP1209

-12.10 库(一)

--LinuxCPP1210

-12.11 库(二)

--LinuxCPP1211

-12.12 makefile文件(一)

--LinuxCPP1212

-12.13 makefile文件(二)

--LinuxCPP1213

-12.14 makefile文件(三)

--LinuxCPP1214

-12.15 编程实践

--LinuxCPP1215

-第十二讲 Linux系统编程基础--编程实践提交入口

第十三讲 进程编程

-13.01 提纲

--LinuxCPP1301

-13.02 进程基本概念

--LinuxCPP1302

-13.03 信号

--LinuxCPP1303

-13.04 进程管理(一)

--LinuxCPP1304

-13.05 进程管理(二)

--LinuxCPP1305

-13.06 进程管理(三)

--LinuxCPP1306

-13.07 进程间通信(一)

--LinuxCPP1307

-13.08 进程间通信(二)

--LinuxCPP1308

-13.09 进程间通信(三)

--LinuxCPP1309

-13.10 进程间通信(四)

--LinuxCPP1310

-13.11 进程池

--LinuxCPP1311

-13.12 编程实践

--LinuxCPP1312

-第十三讲 进程编程--编程实践提交入口

第十四讲 线程编程

-14.1 提纲

--LinuxCPP1401

-14.2 线程基本概念

--LinuxCPP1402

-14.3 线程管理(一)

--LinuxCPP1403

-14.4 线程管理(二)

--LinuxCPP1404

-14.5 线程管理(三)

--LinuxCPP1405

-14.6 线程管理(四)

--LinuxCPP1406

-14.7 线程同步机制(一)

--LinuxCPP1407

-14.8 线程同步机制(二)

--LinuxCPP1408

-14.9 C++11线程库(一)

--LinuxCPP1409

-14.10 C++11线程库(二)

--LinuxCPP1410

-14.11 C++11线程库(三)

--LinuxCPP1411

-14.12 C++11线程库(四)

--LinuxCPP1412

-14.13 C++11线程库(五)

--LinuxCPP1413

-14.14 编程实践

--LinuxCPP1414

-第十四讲 线程编程--编程实践提交入口

第十五讲 网络编程

-15.1 提纲

--LinuxCPP1501

-15.2 Internet网络协议

--LinuxCPP1502

-15.3 套接字(一)

--LinuxCPP1503

-15.4 套接字(二)

--LinuxCPP1504

-15.5 编程实践

--LinuxCPP1505

-第十五讲 网络编程--编程实践提交入口

课程文档

-课程PDF文件

LinuxCPP0704笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。