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____

 

 

 

 

 

 

posted @ 2017-09-11 07:44  elewei  阅读(236)  评论(0编辑  收藏  举报