C 基础 - 结构和联合
1. 结构基本知识
C语言提供 结构变量(struct variable) 来扩展表示数据的能力。
需求:创建一个图书目录。
打印每本书的各种信息: 书名,作者,价格,出版社等。
可以使用C结构来描述数据。
聚合数据类型能够同时存储超过一个单独数据。C提供两种聚合数据类型:
数组与结构
结构是一些值的集合,这些值称为它的成员,但一个结构的各个成员可能具有不同的类型。
每个结构成员都有自己的名字,它们是通过名字访问的。
1.1 结构声明
结构声明描述了一个结构的组织布局
格式: struct tag { member-list } variable-list;
tag 和 variable-list 必须有一个存在
(1) 只有tag的情况
1 struct BOOK { /* structure template: tag is BOOK */
2 char title[MAXTITL]; // 成员
3 char author[MAXAUTL];
4 float value;
5 }; /* end of structure template */
并没有描述实际的数据对象,只是描述了对象由什么组成,所以并未创建任何变量。
可以使用BOOK标签进行如下声明变量
struct BOOK x; /* 创建一个名叫x的变量,变量中有title,author,value三个成员 */ struct BOOK y[20], *z; /* 创建了y和z, y是一个数组,包含了20个BOOK结构, z是一个指向这个类型的结构 */
(2) 只有变量列表的情况
struct { char title[MAXTITLE]; char author[MAXAUTH]; float value; } x, y[20], *z; /* 直接创建了三个和上面相同的变量 */
(3) 使用typedef
/* book.h */
typedef struct { char title[MAXTITLE]; char author[MAXAUTH]; float value; } BOOK; /* 效果与标签相同,但BOOK现在是类型名 */
/* book.c */
#include "book.h"
BOOK x,y[20], *z; /* 声明变量 */
1.2 初始化结构
struct BOOK library = {
"C Primer Plus",
"史蒂芬 普拉达",
"80"
};
还可以使用初始化器来初始化成员
/* 只初始化book结构中 value成员 */
struct BOOK gift = {
.value = 10.99
};
/* 按照任意顺序初始化成员 */
struct BOOK surpise = {
.value = 25.99,
.author = "Steven",
.title = "C Primer Plus"
};
1.3 访问结构成员
(1) 结构成员的直接访问(结构变量.成员名字)
library.value
.value .author .title 相当于结构的下标。
(2) 用指针访问结构中的成员(指向结构的指针->指定的结构成员)
如果 him == &library, 那么him->income
如果 him == &library[0], 那么him->income 即是 library[0].income
另一种方法: & 与 * 是一组互逆运算
fellow[0].income == (*him).income /*一定要加括号,因为.的优先级高*/
结构嵌套
struct names { /* 第一个结构 */
char fist[LNE];
char last[LEN];
};
struct guy {
struct names handle; /* 结构嵌套 */
char favfood[len];
char job[LEN];
float income;
};
struct guy fellow = {
{David Zhang},
"Fish",
"Software Engineer",
"9999.00",
};
/* 访问嵌套中结构的成员 */
fellow.handle.first
一个例子, 有如下的两个结构体
typedef struct { int a; short b[2]; } Ex2; typedef struct EX { int a; char b[3]; Ex2 c; struct EX *d; } Ex;
使用图示的表示Ex如下
新建一个结构体变量x, 并赋初值
Ex x = {10, "abc", {-1, {1, 2} }, 0}; Ex *px = &x;
(1) 如果 执行 px + 1 将会是不合法的,因为 px 是一个指针,指向x,但px + 1 指向一个不确定的内存地址。但编译器无法检测出
这类错误。
(2) 表达式 *px 的值将会是x整个数据结构。 表达式 * px + 1 也是非常法, *(px + 1)也是非法的。
(3) 表达式 px -> a 将会得出10。 -> 操作符对px执行间接访问操作,首先得到它所指向的数据结构,然后访问成员a。
如果你知道结构的名字,可以使用x.a获得相同的值。
*px 与 px -> a 的区别
*px 是一个指向x结构的一个指针,类型为Ex, px -> a 得出一个整形变量10。 但是 *px 与 px->a 指向的地址是相同的。
(4) 创建一个指向整形的指针
int *pi;
表达式 pi = px; 是非法的, 因为类型不匹配,可以使用强制转换,但方法危险。
pi = &px -> a; 该语句为合法语句, -> 的优先级高于&,先执行 px->a 得出10 , 使用&取出a的地址,并让pi指向x.a
(5) px -> b 将会指向一个指针常量,
下面语句输出:
typedef union
{
long i; 16
int k[5]; 5 * 4 = 20
char c; 1
}DATE; 20
struct data {
int cat; 4
DATE cow; 20
double dog; 8
}too; 32
DATE max;
则语句 printf("%d",sizeof(struct date)+sizeof(max));的执行结果是:___52____