结构和其它数据形式
一、概述
在程序设计时,最重要的步骤之一就是选择合适的数据结构来表示数据。在很多情况下,单纯使用基本变量或者数组来表示还不够,为此C语言提供了 结构变量 struct
来提高表示数据的能力。
二、结构变量 struct
为了更好的表述结构变量 struct 的内容,我们以一个图书实例来说明。
以图书为例,一般图书会存在如下几个属性 (
图书名、作者、价格、出版日期
等)。如果单纯以变量来定义图书的各个属性,就会使图书的属性定义显的散乱。
如下所示:
char title[41] = "Book Name"; //书名
char author[31] "Book Author"; //作者
float price = 100.0; //价格
上述代码虽然也可以表示图书的相关属性,但是各个属性间的相关性并不强,不能很直观的将相关的几个属性关联到一起,形成一个对图书的描述。
下面我们看看结构变量 strcut
是如何来描述图书的?
2.1 结构的定义
结构的声明: 使用 struct
来表述一个结构。
// 只定义了结构,但并未让编译器为数据分配空间。
struct book {
char title[41]; //书名
char author[31]; //作者
float price; //价格
};
上面只声明了一个代表图书的结构,但并未将其定义为一个变量。因此编译器并未给这个结构分配空间。
结构变量的定义: 编译器创建了结构变量 library,并为它分配了空间。
下面展示了3种结构的定义。
void main(void) {
// 1.如果之前声明过变量book,可以直接定义。
struct book library;
struct book library1;
// 2.声明和定义一起
struct book {
char title[41]; //书名
char author[31]; //作者
float price; //价格
} library;
// 3.声明和定义一起,省略标记book,但是该结构变量只有一个library。
struct {
char title[41]; //书名
char author[31]; //作者
float price; //价格
} library;
}
结构变量的初始化:
void main(void) {
// 1.定义并同时初始化,类似数组的初始化,结构会根据顺序赋值给结构内的变量。
struct book library = {
"Book Name", //赋值给title
"Book Author", //赋值给author
100.0 //赋值给price
};
// 2.结构初始化器,类似数组可以指定从哪个字段开始赋值,然后按照顺序进行。
struct book library = {
.title = "Book Name", //赋值给title
.author = "Book Author", //赋值给author
.price = 100.0 //赋值给price
};
// 3.结构初始化器
struct book library = {
.price = 90.0, //赋值给price
.author = "Book Author", //赋值给author
100.0 //上一个赋值给author,这个没有指定给哪个结构成员赋值,因此会赋值给author的下个结构成员,即price.
};
// 4.允许直接将一个结构变量赋值给另一个相同结构类型的变量。
struct book library1 = library;
}
访问结构成员: 使用结构成员运算符 .
访问结构中的成员
void main(void) {
struct book library = {
"Book Name", //赋值给title
"Book Author", //赋值给author
100.0 //赋值给price
};
// 访问图书价格
printf("价格:%d", library.price);
}
嵌套结构:
// 作者姓名
struct names {
char first[21];
char last[21];
};
struct book {
char title[41]; //书名
struct names author; //作者 嵌套结构
float price; //价格
};
void main(void) {
struct book library = {
"Book Name", //赋值给title
{"first", "last"},
100.0
}
}
2.2 结构数组
声明结构数组: 声明结构数组和声明其他类型的数组类似,如下所示:
// 声明一个可容纳10个int的数组。
int int_array[10];
// 声明一个可容纳10本图书的数组。
struct book library_array[10];
访问结构数组内元素的成员: 如访问第2本书的价格。
// 声明一个可容纳10本图书的数组。
struct book library_array[10];
// 访问第2本书的价格(默认数组初始化过)。
library_array[1].price;
2.3 指向结构的指针
使用指针的好处:
1.指向结构的指针通常比结构本身容易操控。
2.传递指针比传递结构效率更高(不会产生结构副本)。
声明结构指针: strcut book * p_library;
初始化结构指针: 结构变量名不是结构变量的地址
,因此需要使用 &
来获取结构的地址赋值给结构指针。
用指针访问成员: 结构指针使用 ->
来访问结构成员。
代码示例:
struct book library = {
"Book Name",
"Book Author",
100.0
};
// 1.声明指向图书的结构指针
struct book * p_library;
// 2.将结构变量的地址赋值给结构指针
p_library = &library;
// 3.使用指针访问结构成员
printf("Price = %d", p_library->price);
// 使用结构变量访问结构成员
printf("Price = %d", library.price);
2.4 向函数传递结构的信息
将结构作为函数参数的几种形式:传递结构成员、传递结构地址(指针)、传递结构。
示例:
struct book {
char title[41]; //书名
char author[31]; //作者
float price; //价格
int count; //数量
};
float total_price(float price, int count);
float p_total_price(const struct book * p_book);
float f_total_price(const struct book f_book);
void main(void) {
// 定义一个图书的变量并初始化
struct book library = {
"Book Name",
"Book Author",
100.0, //图书价格
50 //图书数量
};
// 1.传递结构成员
printf("Total price = %.2f", total_price(library.price, library.count));
// 2.传递结构地址(指针)
struct book * p_library;
p_library = library;
printf("Total price = %.2f", p_total_price(p_library));
printf("Total price = %.2f", p_total_price(&library));
// 3.传递结构
printf("Total price = %.2f", f_total_price(library));
// 4.返回一个结构
struct book library_new;
library_new = set_book_price(library);
printf("Total price = %.2f", library_new.price);
}
//传递结构成员
float total_price(float price, int count) {
return price * count;
}
// 传递结构地址
float p_total_price(const struct book * p_book) {
return p_book->price * p_book->count;
}
// 传递结构
float f_total_price(const struct book f_book) {
return f_book.price * f_book.count;
}
// 返回结构
struct book set_book_price(struct book f_book) {
f_book.price = 90;
return f_book;
}
小结:
参数类型 | 结构指针 | 结构 |
---|---|---|
优点 | 传递效率高,不会产生结构副本。 | 数据可被修改(数据安全性问题),可通过 const 修饰参数来确保数据安全性。 |
缺点 | 数据被修改不会影响到原始数据,因为修改的是副本。 | 会产生一个原始数据的副本,增加内存消耗。 |
三、联合结构 union
联合是一种数据类型,它能在同一个内存空间中存储不同的数据类型(不是同时存储)。
联合结构与结构的差异:
1.联合结构与结构基本相同,除了初始化数据上的差异。联合结构同一时刻只会有一个成员有值。
2.联合结构的内存大小:联合成员中占用最大字节的类型的字节大小。
联合结构的声明:
// 联合结构的成员在存储数据时是互斥的,即存储了某个成员,其它成员的数据都会被清除。
union hold {
int digit;
double bigfl;
char letter;
}
定义联合结构的变量:
// 定义联合结构变量
union hold fit;
union hold fit_array[10];
union hold * p_fit;
// 赋值
fit.letter = 'A'; //赋值
p_fit->letter = 'B';
union hold fit_new = fit; //用另一个联合结构来初始化
四、枚举类型 enum
枚举类型的目的是提高程序段可读性,常用枚举类型来定义整型常量。
// 声明颜色的枚举
enum COLOR {
RED,
ORANGE,
YELLOW,
GREEN
};
// 定义枚举变量
enum COLOR color; //enum COLOR 可以当做是一种类型名
五、 typedef
的使用
typedef
是一个高级的数据特性,利用 typedef 可以为某一类型自定义名称,这个与define
类似。typedef
是将现有的类型定义成一个标签,其它地方可以使用这种标签来声明同类型的变量。
typedef 与 define 的不同点:
typedef
创建的符号名只受限于类型,不能用于值。
typedef
由编译器解释,不是预处理器。
示例:
// 将 unsigned char 类型定义为一个BYTE
typedef unsigned char BYTE;
// 使用 BYTE 来定义变量
BYTE x, y;