C语言结构体和其他数据形式(C Primer Plus 第六版)(三)

简介: C语言结构体和其他数据形式(C Primer Plus 第六版)(三)

七、联合简介



联合(union)是一种数据类型,它能在同一个内存空间中储存不同的数据类型(不是同时储存)。其典型的用法是,设计一种表以储存既无规律、事先也不知道顺序的混合类型。使用联合类型的数组,其中的联合都大小相等,每个联合可以储存各种数据类型。


创建联合和创建结构的方式相同,需要一个联合模板和联合变量。可以用一个步骤定义联合,也可以用联合标记分两步定义。下面是一个带标记的联合模板:


union hold {
int digit;
 double bigfl;
 char letter;
};


根据以上形式声明的结构可以储存一个int类型、一个double类型和char类型的值。然而,声明的联合只能储存一个int类型的值或一个double类型的值或char类型的值。


下面定义了3个与hold类型相关的变量:


union hold fit; // hold类型的联合变量


union hold save [10]; //内含10个联合变量的数 union hold * pu; //指向hold类型联合变量的指针


第1个声明创建了一个单独的联合变量fit。编译器分配足够的空间以便它能储存联合声明中占用最大字节的类型。在本例中,占用空间最大的是double类型的数据。在我们的系统中,double类型占64位,即8字节。第2个声明创建了一个数组save,内含10个元素,每个元素都是8字节。第3个声明创建了一个指针,该指针变量储存hold类型联合变量的地址。


7.1 联合和结构体的区别


联合体

用途:使几个不同类型的变量共占一段内存(相互覆盖)


结构体是一种构造数据类型

用途:把不同类型的数据组合成一个整体-------自定义数据类型


八、枚举类型



一个集的 枚举 是列出某些有穷 序列 集的所有成员的程序,或者是一种特定类型对象的计数。


可以用枚举类型((enumerated type)声明符号名称来表示整型常量。使用enum关键字,可以创建一个新“类型”并指定它可具有的值(实际上,enum常量是int类型,因此,只要能使用int类型可以使用枚举类型)。枚举类型的目的是提高程序的可读性。它的语法与结构的语法相同。例如,可以这样声明:


enum spectrum (red,orange,yellow,green,blue,violet} ;
 enum spectrum color;


第1个声明创建了spetrum作为标记名,允许把enum spetrum作为一个类型名使用。第2个声明使color作为该类型的变量。第1个声明中花括号内的标识符枚举了spectrum变量可能有的值。因此,color可能的值是red、orange、yellow 等。这些符号常量被称为枚举符(enumerator)。然后便可这样用:


int c;
color = blue;
if (color == yellow)


8.1 enum的用法


枚举类型的目的是为了提高程序的可读性和可维护性。如果要处理颜色,使用red和 blue 比使用0和1更直观。注意,枚举类型只能在内部使用。如果要输入color中orange的值,只能输入1,而不是单词orange。或者,让程序先读入字符串"orange",再将其转换为orange 代表的值。


因为枚举类型是整数类型,所以可以在表达式中以使用整数变量的方式使用enum变量。它们用在case语句中很方便。


九、typedef简介



typedef 工具是一个高级数据特性,利用typedef可以为某一类型自定义名称。这方面与#define类似,但是两者有3处不同:


与#define不同,typedef创建的符号名只受限于类型,不能用于值。


typedef由编译器解释,不是预处理器。


在其受限范围内,typedef 比#define更灵活。


下面介绍typedef的工作原理。假设要用BYTE表示1字节的数组。只需像定义个char 类型变量一样定义BYTE,然后在定义前面加上关键字typedef 即可:


typedef unsigned char BYTE;


随后,便可使用BYTE来定义变量:


BYTE x, y [10],* Z;


该定义的作用域取决于typedef定义所在的位置。如果定义在函数中,就具有局部作用域,受限于定义所在的函数。如果定义在函数外面,就具有文件作用域。


通常,typedef定义中用大写字母表示被定义的名称,以提醒用户这个类型名实际上是一个符号缩写。当然,也可以用小写:


typedef unsigned char byte;


typedef中使用的名称遵循变量的命名规则。


为现有类型创建一个名称,看上去真是多此一举,但是它有时的确很有用。在前面的示例中,用BYTE代替unsigned char表明你打算用BYTE类型的变量表示数字,而不是字符码


typedef的一些特性与#define的功能重合。例如:


#define BYTE unsigned char


这使预处理器用BYTE替换unsigned char。但是也有#define没有的功能:


typedef char * STRING;


**没有typedef关键字,编译器将把STRING识别为一个指向char的指针变量。有了typedef关键字,编译器则把STRING解释成一个类型的标识符,该类型是指向char的指针。**因此:


STRING name,sign ;


相当于:


*char name, * sign ;


但是,如果这样假设:#define STRING char *然后,下面的声明:

STRING name,sign;


将被翻译成:


char *name, sign;


这导致只有name才是指针。


还可以把typedef用于结构:


typedef struct complex {
 float real;
 float imag;
}COMPLEX;


然后便可使用COMPLEX类型代替complex结构来表示复数。使用typedef 的第1个原因是

**为经常出现的类型创建一个方便、易识别的类型名。**例如,前面的例子中,许多人更倾向于使用STRING或与其等价的标记。


用typedef来命名一个结构类型时,可以省略该结构的标签:


typedef struct ( double x; double y; } rect;


假设这样使用typedef定义的类型名:


rect r1= { 3.0,6.0 ) ;
rect r2 ;


以上代码将被翻译成:


struct { double x; double y; } r1= { 3.0, 6.0 };
struct { double x; double y; } r2;
r2 = r1;


这两个结构在声明时都没有标记,它们的成员完全相同(成员名及其类型都匹配),C认为这两个结构的类型相同,所以r1和r2间的赋值是有效操作。


使用t ypedef的第2个原因是: t**ypedef常用于给复杂的类型命名。*例如,下面的声明;typedef char ( FRPTC ())[5];

把FRPTC声明为一个函数类型,该函数返回一个指针,该指针指向内含5个char类型元素的数组(参见下一节的讨论)。


使用typedef时要记住,**typedef并没有创建任何新类型,它只是为某个已存在的类型增加了一个方便使用的标签。**以前面的STRING为例,这意味着我们创建的STRING类型变量可以作为实参传递给以指向char指针作为形参的函数。

通过结构、联合和typedef,C提供了有效处理数据的工具和处理可移植数据的工具。


十、关键概念



我们在编程中要表示的信息通常不只是一个数字或一些列数字。程序可能要处理具有多种属性的实体。例如,通过姓名、地址、电话号码和其他信息表示一名客户;或者,通过电影名、发行人、播放时长、售价等表示一部电影DVD。C结构可以把这些信息都放在一个单元内。在组织程序时这很重要,因为这样可以把相关的信息都储存在一处,而不是分散储存在多个变量中。


设计结构时,开发一个与之配套的函数包通常很有用。例如,写一个以结构(或结构的地址)为参数的函数打印结构内容,比用一堆printf()语句强得多。因为只需要一个参数就能打印结构中的所有信息。如果把信息放到零散的变量中,每个部分都需要一个参数。另外,如果要在结构中增加一个成员,只需重写函数,不必改写函数调用。这在修改结构时很方便。


联合声明与结构声明类似。但是,联合的成员共享相同的存储空间,而且在联合中同一时间内只能有一个成员。实质上,可以在联合变量中储存一个类型不唯一的值。


enum 工具提供一种定义符号常量的方法,typedef 工具提供一种为基本或派生类型创建新标识符的方法。


指向函数的指针提供一种告诉函数应使用哪一个函数的方法。(这个文章没有更新,用的不多,有需要的话再回来更新)


十一、总结



C结构提供在相同的数据对象中储存多个不同类型数据项的方法。可以使用标记来标识一个具体的结构模板,并声明该类型的变量。通过成员点运算符(.)可以使用结构模版中的标签来访问结构的各个成员。


如果有一个指向结构的指针,可以用该指针和间接成员运算符(->)代替结构名和点运算符来访问结构的各成员。和数组不同,结构名不是结构的地址,要在结构名前使用&运算符才能获得结构的地址。


一贯以来,与结构相关的函数都使用指向结构的指针作为参数。现在的C允许把结构作为参数传递,作为返回值和同类型结构之间赋值。然而,传递结构的地址通常更有效。


联合使用与结构相同的语法。然而,联合的成员共享一个共同的存储空间。联合同一时间内只能储存一个单独的数据项,不像结构那样同时储存多种数据类型。也就是说,结构可以同时储存一个int 类型数据、一个double类型数据和一个char类型数据,而相应的联合只能保存一个int类型数据,或者一个double类型数据,或者一个char类型数据。


通过枚举可以创建一系列代表整型常量(枚举常量)的符号和定义相关联的枚举类型。


typedef 工具可用于建立C标准类型的别名或缩写。

相关文章
C 语言中的数据类型转换:连接不同数据世界的桥梁
C语言中的数据类型转换是程序设计中不可或缺的一部分,它如同连接不同数据世界的桥梁,使得不同类型的变量之间能够互相传递和转换,确保了程序的灵活性与兼容性。通过强制类型转换或自动类型转换,C语言允许开发者在保证数据完整性的前提下,实现复杂的数据处理逻辑。
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
284 14
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
247 10
C 语言中的文件操作:数据持久化的关键桥梁
C语言中的文件操作是实现数据持久化的重要手段,通过 fopen、fclose、fread、fwrite 等函数,可以实现对文件的创建、读写和关闭,构建程序与外部数据存储之间的桥梁。
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
145 23
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
24 1
一文彻底搞清楚C语言的函数
|
3月前
|
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
137 15
|
3月前
|
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
75 24
|
3月前
|
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
129 16
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等