当前课程知识点:基于Linux的C++ >  第六讲 复合数据类型 >  6.5 结构体 >  LinuxCPP0605

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

LinuxCPP0605在线视频

LinuxCPP0605

下一节:LinuxCPP0606

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

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

接下来这个主题是结构体

它的性质和我们的数组是不一样的

数组的所有的元素

它们的元素类型都是相同的

可是我们的结构体可以相同

也可以不同

主要的内容分成了这四个部分:

一个就是结构体的意义和性质

第二个就是结构体的存储表示

第三个就是结构体定义的数据对象

该如何进行访问

第四个就是结构体和函数之间的关系

我们首先来看结构体的意义与性质

从结构体定义的这个角度来讲

和数组的最大差别

它事实上是个不同类型的数据对象的集合

这一点和数组有最大的不同

数组中所有的元素

它的元素类型都是一样的

可是对于我们这个结构体来讲呢

这就不一样

我们来看像这样一个基本的定义

前面使用一个struct

后面跟着一个结构体类型的名称

一个花括号对

里面就是成员类型1

成员名称1 成员类型2 成员类型2……

就按照这样一个方式定义结构体的类型

注意花括号后边

最后是要有一个分号

来表示这个结构体类型的结尾的

那么在定义结构体类型的时候

你要记得 在这里面

它事实上是一系列数据元素

我们称之为字段、域、成员

每个元素的类型

(每个字段的名称)都可以是相同的

也可以是不同的

对于数组来讲

它的每一个成员元素类型

必须是一模一样的

所以在定义的时候

我们只需要指出它的元素类型就够了

可是对于结构体呢 这里面成员的类型

它的类型的名字可以是一样的

可以是不一样的

所以 我们在定义的时候

就不能够用一个就完成

有了这个结构体类型的定义

你当然就可以定义这个结构体类型的变量

我们在讲怎么定义这个变量之前

我们来看几个结构体的例子

你比如讲日期结构体

它实际上包括了年 包括了月 包括了日

每一个我都可以用结构体的成员来表达

三者都定义成一个int

所以你看我会写

struct DATE{ int year; int month; int day}

花括号对结束之后有一个分号

这个就是我们的日期这个结构体

第二个例子就是负数

struct COMPLEX做了一个负数的结构体

这里边有一个实部 有一个虚部

这个实部和虚部

实际上都是double类型的量

这些都叫结构体类型的定义

这里面每个字段都需要描绘得清楚

就像量一样去定义它

但事实上它不是量

它事实上是这个结构体的一个成员

或者一个成分

我们可以说

这个结构体里边有好几个成分

每个成分都是结构体信息的一部分

就相当于它的信息的一个切片

所有这些切片合在一起

才构成了整个完整的结构体类型的描述

还有一种很特殊的情况

在C++代码里边

可以按照“struct COMPLEX;”

这种格式来声明一个结构体类型

注意这里面写出来的struct COMPLEX

它是一个结构体类型的声明

它不是定义

它就没有给出这个结构体的完整的描述

也就是说你缺了花括号对

你没有跟我说明这个成分是什么样子

那么就不叫定义 只能叫声明

仅仅引入这个结构体的名字

以后有些地方

我们只使用名字就可以了的

而有的地方仅仅使用声明是不够的

那么那个时候你就不能够去使用它

我们并没有产生或者创造

新结构体类型出来

我们仅仅是引入它

我们知道

有这样一个结构体类型名字的存在

而不知道它具体的内容是什么

所以你不可以去使用

这样一个格式去定义一个变量

我们来看看实际的例子

我如何来表示

我们一个同学的学生信息呢

我们就来分析

我们解决一个实际问题的时候

结构体是非常非常常用的数据结构

那么针对于学生信息这道题

那我们就要想

我要表达的学生的信息

包括了哪些细节

第一个 我要表达学号

我用什么类型来表达呢 整数

那我可不可以使用一个字符串类型呢

其实都是可以的

那还有一个 名字

其实应该使用字符串类型

还有呢 性别

性别 我们就使用一个枚举型

这是很容易的

年龄 我们可以使用一个整数

你可能说他可能还有电话号码

你可以使用一个字符串

可能有的同学不是一个电话号码

他有固定电话啊 他有手机啊

手机号码可能有两个

碰到这种情况怎么办

一个串型可能就不够了

对于电话来说

可能我们还需要一个数组

但是我们现在呢

实际上并没有真正去讨论

字符串该如何去实现

所以我们假设这里边

已经产生了一个大写的STRING

字符串类型的定义

假设你已经知道了

我们用它来表达一个字符串

那么表达这个结构体类型的时候

就可以按照这样一个模式来去写

第二点 就是结构体的存储表示

结构体类型的变量

将按照它的结构体成员的定义

一个接着一个地顺序去放

这个空间和数组不一样

数组元素的存放是紧挨着放的

结构体这些成员呢

要求一个挨着一个地往下放

但是并不要求它们必须是完全紧密的

为啥呢

就是因为结构体的元素类型

性质是不一样的

可能第一个元素类型是个int

第二个元素类型就变成了STRING

第三个类型可能变成枚举型GENDER

它们的类型是不一致的

所以没有办法完全紧挨着放

还能保证整个程序的运行效率

这个就是我们整个

硬件基础架构所导致的

一个硬件基础架构是32位的

理论上我数据的存放

应该是4的倍数往上放

它的存储效率是高的

所以在这种情况下面

事实上就是为了保证整个程序的效率

它可能在按照顺序

摆放结构体成员的时候

中间可能会出现空洞

这一点是和数组有最大的不同

你要想知道真正结构体存储空间的大小

不要想当然认为它将等于

这些字段的存储空间大小之和

用sizeof操作符获取它

有了这个结构体的类型

我们就可以定义这个结构体类型的变量

你比如说

我定义了DATE类型的一个变量 date

我定义了STUDENT类型的一个变量Zhang_San

还有一种情况呢

比如说我有很多位同学

我就可以用一个数组来表达它

这个数组每一个元素

就是我们结构体类型

STUDENT students[8] 我有8个元素

每个元素都是STUDENT这样的一个结构体

你可以在定义的时候对它进行初始化

不管是常量还是变量

都可以对它进行初始化

你用初始化记号后面跟着花括号对

一个成员、一个成员

对它进行初始化就可以了

中间用逗号来分割开

如果这个成员是个整数

你就按整数的格式对它进行初始化

如果它是字符串

就按照字符串的格式对它进行初始化

有了结构体类型的变量

就可以对这个结构体类型的变量进行赋值

注意 这一点又是和数组有最大的不同

数组是不能够整体赋值的

哪怕这两个数组的元素的个数

是一模一样多的

元素的类型也是一模一样的

要想完成这个数组的赋值

只有一个方案 写一个循环

一个元素 一个元素地拷贝

否则是做不到的

可是我们结构体不一样

你定义了两个结构体类型的变量

只要这两个结构体的类型是一样的

就可以把这个结构体date

赋值给另外一个结构体new_date

它就一个字段 一个字段给你拷贝过去

year拷贝给year

month拷贝给month

day拷贝给day

注意拷贝的这个动作

它只拷贝那个字段的内容

大部分时候这个就是我们所要的结果

但是还有一些很特殊的场合

这种情况可能是不够的

它是一种浅拷贝 层次很浅

如果这个拷贝的深度不够

我们可能需要写一个深拷贝

那个时候就必须你自己写一个函数

来完成这个结构体的赋值的动作

我有了这个结构体类型的变量

那我们怎么访问这个

结构体变量中某一个特定的成员呢

我当然可以整体对它进行访问

就像我刚才讲的

你可以整体对结构体变量进行赋值啊

有的时候我只想访问

它的某一个特定的字段

你比如说这个date

我只想知道它的year信息(年份信息)

是不是2015年

我就要能够访问它的单一的某一个成员

这个时候就需要使用到这个点号操作符

其实称之为成员选择操作符

我选择一个成员year

我就date.year 赋值为2008

这就是一个点号操作符

我们就可以解析出

这个结构体类型变量的

某一个特定的成员

year是这么做 month也这么做

day同样还是这么做

还有一种情况

如果这样一个结构体类型定义的时候

它是嵌套的

你比如讲 我这里有一个类型叫FRIEND

我有一个朋友类型

这个朋友里边有一个字段叫id

有一个字段叫name

还有一个字段birthday

生日是什么类型 年 月 日

这就是一个DATE结构体类型

所以我们有了这个

FRIEND结构体类型的这样一个变量

那我就访问它的

特定的生日这个字段的时候

我就friend.birthday

解析 然后“.year”解析它的年份

也就是说如果这个结构体是个嵌套的

结构体某一个成员还是一个结构体类型

我想访问内部结构体某个成员的时候

就用连续的点号操作符去解析它

还有一种情况

我的朋友可能还不是一个

所以有friends这样一个数组

假设我这里面记录4个朋友

我想访问0号元

那就friends[0].birthday.year

如果是1号元friends[1].birthday.year

按照这个方式进行访问

你看着就觉得好怪

中括号后面就跟着打点

没问题 它就按照这个格式

friend[0]、friends[1]

它得到的就是那个数组元素

那个类型是什么 是个结构体

只要是结构体名字

就可以后面直接打点号解析

一旦解析出来

它就可以像一个普通量一样使用

最后一个主题

关于结构体和函数之间的关系

我们来看这样一个例子

写一个函数 使用一个结构体类型

来存储我们的日期

我们来计算这一天它是今年的第几天

具体天数从1开始计算

你比如2016年1月20号

它是这一年的第几天呢

它就是第20天

那2月1号多少天 32天

我用那个函数来展示什么呢

来展示的就是我们这个结构体

怎么样来作为我们整个函数的参数

GetDateCount这个函数

传一个date作为它的参数

返回值就是它的天数

这个程序该怎么做才能快

我就想一招

1月份 我就直接看它的日期是多少天

如果是2月份呢 它日期是几号

那是它2月是多少天

此前我必须把这个1月全部的天数给加上

如果是3月呢

那个几号就要加上第一月

和第二个月全部的天数

还有一个重要地方

如果是个闰年呢 3月以后

你得要把闰年闰的那一天给加上

如果是非闰年 那一天肯定是不存在的

如果是闰年 月份又在2月份之前

在这种情况下你又不用加

哪怕是2月28号 2月29号它都不用加

因为传过来天数就是那一天

也就是说 我要写一个for循环

我从1月开始去计算

然后这个month天数

累加到month-1那一月份

把这个以前的月份的天数全部加在一起

然后我就要去判断它是闰年不是

如果是闰年

而且这个月份是3月以后(包含3月)

我就把闰年那一天给加上

否则就不用管

我怎么样才能让我这个程序做最快

我们这里面能够处理的最重要一个地方

就是月份这个天数

我1月份31天

2月份多少天

非闰年28天 闰年29天

3月份31天

我们直接做一个数组存起来

我这个数组定义好

days_of_months

定义像这样一个数组

把某一个月所有天数全都存起来

我这个数组定义很特殊

定义13个元素 我们其实就12个月

但我定义13个元素

1月份就在1号元上

2月份就在2号元上

不需要每次做一个减法运算

按照这个方式我们程序就快

这样一个数组 我定义成一个static

我不用每次进入这个函数都创建一遍

然后你就可以用for循环累加

这个月之前的全部月份的日期

然后累加这一月的天数

然后判定它的月份是不是大于2

如果是月份大于2的

然后它是个闰年的

那我就累加 加一天

最后返回日期就OK了

这是第一个例子

第二个例子 就是结构体

还可以作为函数的返回值

这一点还是和数组不一样的

我们前面讲数组是不能整体赋值的

所以数组本身

是不能够作为函数返回值的

可是我们这个结构体是可以整体赋值的

所以它就可以作为函数的返回值

你比如讲我可以生成一个

二维平面上的点坐标

像二维点 有x轴、y轴

我定义了一个结构体类型叫struct POINT

然后我就可以生成像这样二维的点

使用前面的随机数库随机生成

这样的点范围在0~1920

0~1200

GenerateRandomNumber生成随机数

给它定义POINT类型的变量t

然后t.x、t.y 生成出来

生成完了以后 我们return

这就是结构体

作为函数的返回值的时候该怎么用

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

LinuxCPP0605笔记与讨论

也许你还感兴趣的课程:

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