C — 结构和其它数据形式

一、概述

在程序设计时,最重要的步骤之一就是选择合适的数据结构来表示数据。在很多情况下,单纯使用基本变量或者数组来表示还不够,为此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;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值