建立结构声明

结构声明(structure declaration)描述了一个结构的组织布局

struct book
{
char title[MAXTITL];
char author[MAXAUTL];
float value;
};

该声明描述了一个由两个字符数组和一个 float 类型变量组成的结构。该声明并未创建实际的数据对象,只描述了该对象由什么组成

关键字 struct,它表明跟在其后的是一个结构,后面是一个可选的标记(该例中是 book),程序中可以使用该标记引用该结构

在结构声明中,用一对花括号括起来的是结构成员列表。

每个成员都用自己的声明来描述,例如,title 部分是一个内含 MAXTITL 个元素的 char 类型数组

成员可以是任意一种 C 的数据结构,甚至可以是其他结构

右花括号后面的分号是声明所必需的,表示结构布局定义结束

struct book library;

这把 library 声明为一个使用 book 结构布局的结构变量

可以把这个声明放在所有函数的外部,也可以放在一个函数定义的内部

如果把结构声明置于一个函数的内部,它的标记就只限于该函数内部使用

如果把结构声明置于函数的外部,声明结构之后的所有函数都能使用它的标记

例如,在程序的另一个函数中,可以这样声明

struct book dickens;

该函数便创建了一个结构变量 dickens,该变量的结构布局是 book

结构的标记名是可选的

定义结构变量

结构有两层含义

一层含义是“结构布局”,结构布局告诉编译器如何表示数据,但是它并未让编译器为数据分配空间

另一层含义是创建一个结构变量

struct book library;

编译器执行这行代码便创建了一个结构变量 library,编译器使用 book 模板为该变量分配空间

在结构变量的声明中,struct book 所起的作用相当于一般声明中的 int 或 float

struct book library;

相当于

struct book
{
char title[MAXTITL];
char author[MAXAUTL];
float value;
} library; // 声明的右花括号后跟变量名

声明结构的过程和定义结构变量的过程可以组合成一个步骤

组合后的结构声明和结构变量定义不需要使用结构标记

struct // 无结构标记
{
char title[MAXTITL];
char author[MAXAUTL];
float value;
} library;

初始化结构

初始化一个结构变量(ANSI 之前,不能用自动变量初始化结构,ANSI 之后可以用任意存储类别)与初始化数组的语法类似

struct book library = {
"Hello World",
"Jack",
22.1
};

使用在一对花括号中括起来的初始化列表进行初始化,各初始化项用逗号分隔

如果初始化静态存储期的变量(如,静态外部链接、静态内部链接或静态无链接),必须使用常量值,这同样适用于结构。如果初始化一个静态存储期的结构,初始化列表中的值必须是常量表达式。如果是自动存储期,初始化列表中的值可以不是常量

访问结构成员

使用结构成员运算符——点(.)访问结构中的成员

例如,library.value 即访问 library 的 value 部分。虽然 library 是一个结构,但是 library.value 是一个 float 类型的变量,可以像使用其他 float 类型变量那样使用它

. 比 & 的优先级高

结构的初始化器

C99 和 C11 为结构提供了指定初始化器(designated initializer),其语法与数组的指定初始化器类似

结构的指定初始化器使用点运算符和成员名(而不是方括号和下标)标识特定的元素

例如,只初始化 book 结构 value 成员

struct book library = {.value = 10.99};

可以按照任意顺序使用指定初始化器

struct book library = {
.title = "Hello World",
.value = 10.99,
.author = "Jack"
};

与数组类似,在指定初始化器后面的普通初始化器,为指定成员后面的成员提供初始值

对特定成员的最后一次赋值才是它实际获得的值

struct book library = {
.value = 10.99,
.author = "Jack",
22.55
};

value 最后的值为 22.55

结构数组

声明结构数组

声明结构数组和声明其它类型的数组类似

struct book library[MAXBKS];

把 library 声明为一个内含 MAXBKS 个元素的数组,数组的每个元素都是一个 book 类型的数组

数组名 library 本身不是结构名,它是一个数组名,该数组中的每个元素都是 struct book 类型的结构变量

标识结构数组的成员

标识结构数组中的成员,可以采用访问单独结构的规则:在结构名后面加一个点运算符,再在点运算符后面写上成员名

library[0].value  // 第 1 个数组元素与 value 相关联
library[4].title // 第 5 个数组元素与 title 相关联

数组下标是在 library 后面,不是在成员名后面

使用 library[2].value 的原因是,library[2] 是结构变量名

library[2].title[4] 的意思是,library 数组第 3 个结构变量中 title 的第 5 个字符

总结一下:

library              // 一个 book 结构的数组
library[2] // 一个数组元素,该元素是 book 结构
library[2].title // 一个 char 数组(library[2] 的 title 成员)
library[2].title[4] // 数组中 library[2] 元素的 title 成员的第 5 个字符

嵌套结构

在一个结构中包含另一个结构

#include <stdio.h>
#define LEN 20 const char * msgs[5] = {
" Thank you for the wonderful evening, ",
"You certainly prove that a ",
"is a special kind of guy. We must get together",
"over a delicious ",
" and have a few laughs"
}; struct names { // 第 1 个结构
char first[LEN];
char last[LEN];
}; struct guy { // 第 2 个结构
struct names handle; // 嵌套结构
char favfood[LEN];
char job[LEN];
float income;
}; int main(void){
struct guy fellow = {
{"Ewen", "Villard"},
"grilled salmon",
"personality coach",
68112.00
}; printf("Dear %s, \n\n", fellow.handle.first);
printf("%s%s.\n", msgs[0], fellow.handle.first);
printf("%s%s\n", msgs[1], fellow.job);
printf("%s\n", msgs[2]);
printf("%s%s%s\n", msgs[3], fellow.favfood, msgs[4]);
if (fellow.income > 150000.0)
puts("!!");
else if (fellow.income > 75000.0)
puts("!");
else
puts(".");
printf("\n%40s%s\n", " ", "See you soon,");
printf("%40s%s\n", " ", "Shalala"); return 0;
}

运行结果

访问嵌套结构的成员,需要使用两次点运算符

指向结构的指针

就像指向数组的指针比数组本身更容易操纵(如,排序问题)一样,指向结构的指针通常比结构本身更容易操纵

在一些早期的 C 实现中,结构不能作为参数传递给函数,但是可以传递指向其他结构的指针

即使能传递一个结构,传递指针通常更有效率

一些用于表示数据的结构中包含指向其他结构的指针

#include <stdio.h>
#define LEN 20 struct names {
char first[LEN];
char last[LEN];
}; struct guy {
struct names handle;
char favfood[LEN];
char job[LEN];
float income;
}; int main(void){
struct guy fellow[2] = {
{
{"Eween", "Villard"},
"grilled salmon",
"personality coach",
68112.00
},
{
{"Rodeny", "Swillbelly"},
"tripe",
"tabloid editor",
432400.00
}
};
struct guy * him; // 这是一个指向结构的指针 printf("address #1: %p #2: %p\n", &fellow[0], &fellow[1]);
him = &fellow[0]; // 告诉编译器指针该指向何处
printf("pointer #1: %p #2: %p\n", him, him + 1);
printf("him->income is $%.2f: (*him).income is $%.2f\n",
him->income, (*him).income);
him++; // 指向下一个结构
printf("him->favfood is %s: him->handle.last is %s\n",
him->favfood, him->handle.last); return 0;
}

运行结果

声明和初始化结构指针

struct guy * him;

首先是关键字 struct,其次是结构标记 guy,然后是一个星号(*),其后跟着指针名

该声明并未创建一个新的结构,但是指针 him 现在可以指向任意现有的 guy 类型的结构

例如,如果 barney 是一个 guy 类型的结构变量,可以这样写

him = &barney;

结构变量名不是结构的地址,因此要在结构变量名前面加上 & 运算符

在上面代码中 fellow 是一个结构数组,这意味着 fellow[0] 是一个结构。要让 him 指向 fellow[0],可以这样写:

him = &fellow[0];

him 指向 fellow[0],him + 1 指向 fellow[1]

him 加 1相当于 him 指向的地址加 84

在十六进制中,874 - 820 = 54(十六进制)= 84(十进制)

因为每个 guy 结构都占用 84 字节的内存:name.first 占用 20 字节,name.last 占用 20 字节,favfood 占用 20 字节,job 占用 20 字节,income 占用 4 字节(float 占用 4 字节)

用指针访问成员

第 1 种方法是:使用 -> 运算符,该运算符由一个连接号(-)后跟一个大于号(>)组成

如果 him == &barney,那么 him->income 即是 barney.income

如果 him == &fellow[0],那么 him->income 即是 fellow[0].income

第 2 种方法是:以这样的顺序指定结构成员的值,如果 him == &fellow[0],那么 *him == fellow[0],因为 & 和 * 是一对互逆运算符

fellow[0].income == (*him).income

必须要使用圆括号,因为 . 运算符比 * 运算符的优先级高

如果 him 是指向 guy 类型结构 barney 的指针,下面的关系恒成立

barney.income == (*him).income == him->income  // 假设 him == &barney

C Primer Plus学习笔记(十三)- 结构和其他数据形式的更多相关文章

  1. java之jvm学习笔记十三(jvm基本结构)

    java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...

  2. python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容

    python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...

  3. Go语言学习笔记十三: Map集合

    Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...

  4. tensorflow学习笔记——使用TensorFlow操作MNIST数据(2)

    tensorflow学习笔记——使用TensorFlow操作MNIST数据(1) 一:神经网络知识点整理 1.1,多层:使用多层权重,例如多层全连接方式 以下定义了三个隐藏层的全连接方式的神经网络样例 ...

  5. SQL反模式学习笔记18 减少SQL查询数据,避免使用一条SQL语句解决复杂问题

    目标:减少SQL查询数据,避免使用一条SQL语句解决复杂问题 反模式:视图使用一步操作,单个SQL语句解决复杂问题 使用一个查询来获得所有结果的最常见后果就是产生了一个笛卡尔积.导致查询性能降低. 如 ...

  6. 机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据

    机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据 关键字:PCA.主成分分析.降维作者:米仓山下时间:2018-11-15机器学习实战(Ma ...

  7. tensorflow学习笔记——使用TensorFlow操作MNIST数据(1)

    续集请点击我:tensorflow学习笔记——使用TensorFlow操作MNIST数据(2) 本节开始学习使用tensorflow教程,当然从最简单的MNIST开始.这怎么说呢,就好比编程入门有He ...

  8. 【转】Pandas学习笔记(二)选择数据

    Pandas学习笔记系列: Pandas学习笔记(一)基本介绍 Pandas学习笔记(二)选择数据 Pandas学习笔记(三)修改&添加值 Pandas学习笔记(四)处理丢失值 Pandas学 ...

  9. yii的学习笔记 基本结构 自用

    Yii 学习笔记 W:YII是什么? Q:Yii 是一个基于组件的高性能 PHP 框架,用于快速开发大型 Web 应用.它使Web开发中的 可复用度最大化,可以显著提高你的Web应用开发速度.Yii ...

  10. 《C++ primer》学习笔记整理

    简介 本笔记目前已包含<C++ Primer>中的绝大部分内容,但尚有部分小节有所缺漏,如 19.1.19.2 节的笔记尚未整理,会持续更新. 本项目中的学习笔记是在学完一章内容后,对其要 ...

随机推荐

  1. IOS-通讯录

    一.通讯录简介 iOS提供了AddressBook.framework框架,允许开发者与设备中的通讯录进行数据交互   二.查询授权状态 可以调用ABAddressBookGetAuthorizati ...

  2. ORACLE expdp \ impdp \ exp \ imp

    (转自:http://www.cnblogs.com/lanzi/archive/2011/01/06/1927731.html) EXPDP命令行选项1. ATTACH该选项用于在客户会话与已存在导 ...

  3. C# List 排序

    (转自:http://www.cnblogs.com/bradwarden/archive/2012/06/19/2554854.html) 第一种:实体类实现IComparable接口,而且必须实现 ...

  4. Android studio 导入ApiDemo

    1.import 项目,sdk目录:sdk\samples\android-21\legacy\ApiDemos,import时一直下一步就ok了. 2.Error:Error: The file n ...

  5. vue: data binding

    1.文本 第一种“Mustache” 语法(双大括号)写法第二种 用v-text的指今写法第三种和第四是对es6写法的拓展写法,称模板字符串 <template> <div> ...

  6. .net 学习路线感想(转)

    从上到大学到现在工作,已经有六年多了,发现学习编程到以开发为工作也是一个挺长的过程的. 大学中,从c语言到java.C#到其他各种语言的学习,还有其他知识的学习如:数据库(oracle.sql Ser ...

  7. git合并分支与解决冲突

    前提: 当前开发的分支为feature/20161129_317606_algoplatform_1,由于feature/20161130_322574_tmstools_1分支有新内容,所以准备将f ...

  8. Android 仿淘宝属性标签页

    直接看效果图相信这样的效果很多,我之前在网上找了很久没找到自己想要的! <?xml version="1.0" encoding="utf-8"?> ...

  9. 当导用模块与包的import与from的问题(模块与包的调用)

    当在views.py里写impor models会不会报错呢? 1.Python里面的py文件都是每一行的代码. 2.Python解释器去找一个模块的时候,只去sys.path的路径里找 3.djan ...

  10. [STM32]HardFault 定位办法

    网上关于HardFault的定位办法好多,试到了其中一种可行的 http://www.cnblogs.com/Ilmen/p/3356147.html 特此纪录.