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

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

LinuxCPP0705在线视频

LinuxCPP0705

下一节:LinuxCPP0706

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

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

我们来看这样一个例子

随机生成八个整数保存到数组里边

然后颠倒数组的元素

使用指针来去实现它

这个题实际上我们前面已经实现过

不过那个时候我使用的数组来实现的

现在怎么使用指针来去操纵它

前面代码是一样的 需要使用“random.h”

有一个数组操纵的库叫“arrmanip.h”

数组元素当然还是8个

主程序其实也没变

定义数组int a[NUMBER_OF_ELEMENTS]

然后GenerateIntegers生成这8个整数

然后输出信息

把这个8个元素都打印一遍

调用ReverseIntegers把它颠倒过来

再然后PrintIntegers把它再打印一遍

看运行的结果正不正确

main函数和原来的实现其实是一样的

使用指针来实现我们这个库的

所以这些实现

就和以前那个版本不一样了

GenerateIntegers

第一个参数int *p

第二个参数unsigned int n

这是GenerateIntegers

第二个函数ReverseIntegers

第一个参数int *p

第二个参数unsigned int n

第三个函数Swap 交换

因为我要交换是数组中的两个元素值

所以我要传的是指向这两个元素的指针

就直接传int *p、int*q传两个指针

然后PrintIntegers打印它

const int *p指向常整数的一个指针

因为打印的时候

我不会修改这个数组元素的内容的

所以这个地方要加const

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

具体的实现有个lower_bound和uupper_bound

是10到99之间

这个实际上生成的函数叫GenerateIntegers

我们已经解释过了

第二个你要看到的就是ReverseIntegers

怎么对调数组中的元素

传进来的p这个指针

它将是指向数组0号元的一个指针

然后后面n就是这个数组的元素个数

对调这个数组的时候

实际上将要对调的是数组0号元和7号元、

1号元和6号元的数据

你看到它们之间有什么关系

关系就是我们对调的这两个数据

的元素下标之和刚好是元素个数减1

记住这个就可以了

所以对调的是第i号元和n-i-1号元

两者之和刚好是n减1

我们元素个数是n嘛

那么第i号元

哪一个指针会指向它呢 p+i啊

n-i-1号元是p+n-i-1啊

所以我们Swap对调的就是p+i和p+n-i-1

这两个指针所指向的目标数据对象

实际对调的时候还是标准三步互换

然后是PrintIntegers

我们要打印这个数组全部的元素

for循环里边打印它

设置场宽之后打印它的第i号元

我p+i得到的是它的i号元吗

错 得到的是第i号元的地址

P+i本身是指向第i号元的指针

所以要引领才成 我要*(p+i)才成

但是这个地方没有括号是不对的

没有括号就变成*p了

取出来目标值然后再加i了

因为这个新号操作符的优先级

是远远的高于这个加法的

要p+i找到i号元

然后括号外去引领它 “*”引领它

我们就能够PrintIntegers

整个这个程序实现完了

你会看和我们原来数组那个方案

得到的结果是一模一样的

所以从某种程度来讲

我既可以通过这个指针来解决这个问题

也可以通过数组来解决这个问题

两者的实现方案

你看实际上是几乎没差别

内部实现是有差别

但是从外界来看的话

给出来的结果是没差别的

从某种程度来讲

我们就知道指针和数组是可以互换的

指针一旦指向一个数组基地址

那么是使用指针来操作这个数组

还是使用数组格式来操作这个数组

地址计算方式是一模一样的

你比如讲如果我有一个一维数组

int a[3] 然后int *p初始化成数组的基地址

for(i=0; i<3;i++),cout << p[i]

这个方式是对的

p是数组是吗 不是

是指向这个数组的0号元的指针

但是 你就可以把p

当做数组一样的用p[i]

有的初学者在这个问题就会犯糊涂

这是意味着什么呀

这个地方写a[i]是对的

写p[i]是对的

你一下子就能够反应出来

那a就等于等于p啊

那a就是p ,p就是a啊

否则怎么可以这么替换呢

如果是这样

那指针不就是指向那个数组吗

可是我前面不是说过了吗

这指针是指向那个数组吗

指针不是指向那个数组

指针仅仅指向这个数组的0号元

不是指向那个数组

所以有很多初学者在这个问题上

就会犯糊涂了

为啥可以互换呢

唯一的原因就是用指针的方式

来取这个数组i号元的基地址

还是用数组的方式

来取这个数组i号元的基地址

两者的计算格式是一样的

并不意味着这么写法a就和p是等价的

不是的 是它的计算方式是等价的

所以我们才可以这么写

在这种情况下面

一旦这个指针p指向这个数组的0号元

那么你就可以把p这个量本身

当做一个数组名字一样用p[i]

第二个 把这个数组当做一个指针来用

你比如说我可以这么写:*(a+i)

取的就是这个数组的第i号元

a+i得到的就是这个数组的

第i号元的基地址

我们前面不说了吗

这个数组的第i号元的基地址

是怎么得到的

假设这个数组的基地址是p

p+i*sizeof(int)

C/C++设计者啊

他认为如果让你每次在i上面

都乘上sizeof(int)

太麻烦 不需要你写

自动在i上乘上以后

再累加到a的基地址上

所以你就可以直接这么写

*(a+i)就表示取这个数组的第i号元

可以赋值给别人 可以被赋值

取的就是它 那你这么一看

那a和p不还是等价的吗

我们用指针的话不就是*(p+i)嘛

这就是说 在某种程度上讲

指针和数组是等价的 可以互换

可以把一个指针当成一个数组

可以把一个数组当成一个指针

注意 这并不是全部的应用场合

在一维数组上面是有效的

一旦到了高维它可能就是无效的了

指针和数组真是完全等价的吗

当然也不是 它还是有一些例外的

数组名字本身 它是一个常数

你不能够在这个数组格式上面

进行一些特定指针运算的

有些指针运算是不可以的

你比如是这样 指针p是可以被赋值的

所以你*p++ 这是没有问题的

如果它是一个数组的名字

*a是可以的 但是你*a++是不可以的

为啥 a++你不能做

a作为一个数组的名字

它代表的就那个数组的基地址

它事实上是一个常数

你是不可以做a++的

你可以在上面做a+1、a+2

你不可以做a++

因为a++不是a+1

a++它是a+1赋值给a

因为a是一个常数 它不能被赋值

而p 它可以被赋值

它是指针量 就这一点差别

导致指针和数组的互换性是有例外的

我们可以对指针和数组的关系

做一些总结

使用指针和数组来声明这样的

一个数据对象

它的这个性质是不一样的

如果你int a[3]

那么就定义了3个元素的这个数组

正常情况下面

我们会为这三个元素都分配存储空间

它们依序地存放

如果我用int *p 定义像这样的一个量

那么它会为p分配一个存储空间

这个存储空间有多大呢

我们现在的32位计算机、32位的编译器

p是4个字节

那int a[3]多大呢 12个字节

每一个整数是4个字节

总共3个整数 12个字节

所以分配空间是不一样的

你如果将p初始化成&a

a的基地址

那么p将会“指向a那个数组”

但是它并不是那个数组

这是一个指针量

它指向一个数组的0号元

定义指针的时候

规定的是指针数据对象的存储空间

定义数组的时候

它规定的是数组元素的存储空间

这两者是不一样的

所以说如果是一个全局数组

你比如说a为静态分配的这样一个数组

程序运行前就会分配空间

每个元素每个元素就按照顺序放好了

如果你定义一个指针

它就不会为那个数组分配空间

它只分配指针这个对象的空间

如果这个指针指向那个数组

你必须保证那个数组已经分配了

其他地方分配的跟这个指针没关系

除非你是动态分配的

所以当你使用指针的时候 要特别记住

指针这个对象和指针所指向的目标数据对象

两者之间的关联

在你程序里边必须显示地构造它

要完成这一点

还有一个技术细节

是多维数组作为函数参数

如果是一维数组作为函数参数的时候

我们说最恰当的

参数传递的方式就是写int a[]

中括号里边什么也不写

后面跟着第二个参数

传数组的元素个数

这是最正确的一个方案

如果是个多维数组

这个情况就有点问题

第一个 打印二维的一个数组

PrintTwoDimensionalArray

比如说8乘8的这样一个数组

你如果按照第一种这个方案

我直接传递这个数组的

元素个数 这个方案是不妥的

如果没有这个后面两个参数

这个函数写下来 它就受限

因为你封装这个魔数 8和8

两个魔数8就进去了

它就只能处理8乘8的数组

8乘9的处理不了 9乘8的处理不了

10乘10的处理不了

我怎么办呢 后面带参数

传两个参数m、n

传它有多少行m行

有多少列呢 n列

我这里面不使用8乘8的这个信息

我使用m乘n这样一个信息来编程序

这样就保证程序

就和这个魔数8没关系了

还是不妥当 为啥

就是这里面还是这个魔数

仍然没有取消掉

这个程序这么写 它是对的

但是有那么一点不妥当的地方

如果这个魔数你真地都不写 不行

语法规范要求 两个中括号里边

你只能有一个中括号不写

不管这个数组元素个数有几维

一维数组可以不写

二维数组只能第一个中括号里面

什么都不写

三维数组也只能第一个中括号里面

什么都不写

后面你都必须给写上

没有数据是不对的 编译器是通不过的

我们还有一种方案

把二维数组当一维数组降维

有什么不行的呢

先存第一行 后存第二行 再存第三行

不按照这个方式存的吗

既然是这样

那我干脆把所有行当成一行算了

然后按照一维方式来去写

你比如说这个指针

就按照这个方式写:int *a

传 m行n列 那么我们怎么取a[i][j]

第i行第j列这个元素呢

简单 用指针运算 就是a+n*i+j

我们就按照这个方式来算

但是它也是不妥当的

从某种程度来讲

它明明是一个二维数组

你非要把它降为成一维

这个行吗 这个行

但是逻辑上总觉得有点怪

更别说它的运算很复杂

i、j下标的时候去找

要a+n*i+j 这个方式有点小麻烦

到了高维数组以后三维以上 这么算

能不能算出来 都不好说了

到了高维 降维都有可能会出问题

理论上来讲应该没问题

但是你去算它哪一个元素的时候

它就可能会有问题

所以实际上也还是不妥的

那你说 我有没有一个妥当的方案呢

很抱歉 没有

不管是C还是C++里边

当多维数组作为函数参数传递的时候

就没有一个好方案能够解决这个问题

所以说实在没招 我建议同学们

都按照第一个方案写

我们现在来看这样一个例子

刚才第三种方案

使用一个指针对一个二维数组进行降维

我们怎么来访问它

传指针参数 传m行n列的信息

然后在内部降维

每次想访问a[i][j]这号元素的时候

要+n*i+j 括号外用“*”去引领

按照这个方式

接下来一个主题就是指针和结构体的关系

指针可以指向一个结构体

我有一个struct STUDENT结构体

定义一个pstudent

这样一个指针指向一个STUDENT结构体

然后把它初始化成student的基地址

要用指针来访问目标结构体

我要引领

*pstudent得到那个目标结构体

然后要成员解析 打点取id

这个地方必须写括号

因为那个点号操作符的优先级高

你不加括号它会认为pstudent

是一个结构体

然后取它的id的这个成员

而这个id是一个指针

然后引领这个成员

所指向的那个目标数据对象那就不对了

所以我们这里面应该是(*pstudent)

括号完毕之后打点取id

没辙 语法规范的要求必须这么写

C/C++提供了一个新的操作符

叫做“->”操作符

跟我们成员选择“.”操作符是一样的

还是一个选员操作符

表示pstudent是一个指针

它指向一个结构体

我想取目标结构体id成员

那我就直接这么写 pstudent->id

比刚才写的方便了吧

刚才要用4个符号

现在俩符号就够了

不需要写一个括号对了

这样的方案当然要比刚才那个方案

看上去要好写得多

指针和结构体当然不会这么简单

那如果我一个结构体成员

是一个指针会是什么样子

我定义一个struct ARRAY结构体

它里面带着一个数组元素个数count

后面跟着一个指向整数的指针elements

这个elements会指向什么呢

它将会指向我们实际数组的

0号元、1号元、2号元

按照这个方式

我们这里面有个int a[8]

定义好这个数组

然后构造这个数组array

把它初始化

当我想访问这个elements数组

它的第i个元素的时候怎么写呢

我就这么写array.elements[i]

也就说把elements这个指针

当做一个数组一样用

如果你还有一个定义

parray本身就是一个指针

并且我们把它初始化成array这个基地址

那么你想访问parray所指向的

那个目标结构体中的那个成员

所指向的数组的第i号元

我怎么访问呢 那你就这么写(*parray)

就引领它

括号完毕之后打点取elements[i]

取它的i号元

或者你这么写:parray->elements[i]

取到了parray这个指针

所指向的那个结构体的elements那个成员

所指向的那个目标数组的第i号元

结构体指针

有两个非常重要的使用场合

使用指向结构体对象的指针

来作为函数的参数

它有两个好处 第一个

可以节省结构体整体赋值的时间成本

我们讲作为函数参数

你要传一个结构体 它将是整体赋值的

你如果没有使用引用

它就必须按照这个方式来

如果结构体尺寸很大效率肯定是低的

使用指针 问题就简单了

所以一传 传的是结构体的地址

所以这种情况下传结构体的地址

要比结构体整体赋值快得多

第二个 普通结构体类型的参数

作为参数传进去 它不能把结果带回来

我们就觉得不方便

我们想带回来结果 传它的指针

它那个结果就能带回来了

你又想快 又不想带回来结果呢

就指向const结构体的指针

第二个使用场合

构造复杂的数据结构

我想创建一个数据结构

这个数据结构能够表达

动态的数组信息

表达数组元素个数

可以在整个程序运行期间

随时发生变化的数据结构

它里边保存了一系列元素

这些元素个数

可以在程序运行期间动态的变化

可以大 也可以缩小

这个我们就称它为动态数组

我们就需要使用很特殊的

像这样的数据结构:struct ARRAY

它实际上是用一个结构体

来表达一个数组的概念

这里面包含了一个元素的个数

这个数组元素个数是多少个count个

用一个int * elements来表达

指向特定元素的指针

以后就可以通过elements指针的运算

来访问它的0号元、1号元、2号元

这个就叫动态数组

你定义好了这个数据结构

必须为它创建一系列对动态数组

进行操作的函数

基于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文件

LinuxCPP0705笔记与讨论

也许你还感兴趣的课程:

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