1、联合
联合(union)是一种数据类型,它能在用一个内存空间中存储不同的数据类型(但不是同时存储)。其典型的用法是,设计一种表以存储既无规律、事先也不知道顺序的混合类型。 使用联合类型的话,其中的联合都大小相等,每个联合可以存储各种数据类型。
联合体的特点是所有成员共用一块内存空间。所以联合体也叫:共用体。 创建联合和创建结构的方式相同,需要一个联合模板和联合变量。
下面是一个带标记的联合模板:
union hold
{int dight;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类型联合变量的指针
第一个声明创建了一个到哪都的联合变量fit。 编译器分配足够的空间以便它能存储联合声明中占用最大字节的类型。 在本例中,占用空间最大的double 类型的数据, 在我们的系统中,double类型占64位,即8字节。 第二个声明创建了一个数组save,内含10个元素,每个元素都是8字节。第3个声明创建了一个指针,该指针变量存储hold类型联合变量的地址。
#include <stdio.h>
union hold
{int dight;double bigfl;char letter;
};
int main()
{union hold u = { 0 };printf("%p\n", &u);printf("%p\n", &(u.bigfl));printf("%p\n", &(u.dight));printf("%p\n", &(u.letter));return 0;
}
运行结果:
我们发现。这4个地址都相同。所以,也就是说明联合体共用一块内存空间。
联合体的大小
我们来看看下面的代码:
#include <stdio.h>
union Un1
{char c[5];int i;
};
union Un2
{short c[7];int i;
};
int main()
{//下⾯输出的结果是什么?printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));return 0;
}
结果: 。这是为什么呢?
其实联合体和结构体一样,都有最大对齐数。但又和结构体有所不同。
在Un1中,char类型占1个字节,有5个char共占用5个字节,int类型,占用4个字节。默认对齐数是8,又因为联合体共用一块内存空间,所以总共占用8字节。在Un2中,short类型的c数组共占用14个字节,int类型占4个字节。按最大对齐数的整数倍占用空间,所以是16个字节。
联合体共用一块内存空间,所以只能同时使用一个。比如说,我使用变量dight,就不能使用bigfl和letter变量,因为空间被dight使用了。
2、枚举
枚举是 C 语言中的一种基本数据类型,用于定义一组具有离散值的常量,它可以让数据更简洁,更易读。
枚举类型通常用于为程序中的一组相关的常量取名字,以便于程序的可读性和维护性。
定义一个枚举类型,需要使用 enum 关键字,后面跟着枚举类型的名称,以及用大括号 {} 括起来的一组枚举常量。每个枚举常量可以用一个标识符来表示,也可以为它们指定一个整数值,如果没有指定,那么默认从 0 开始递增。
声明枚举类型
enum spectrum
{red,orange,yellow,green,blue,violet
};
enum spectrum color;
第1个声明创建了作为标记名,允许把enum spectrum作为一个类型名使用。第2个声明使color作为该类型的变量。第1个声明中花括号内的标识符枚举了spectrum变量可能有的值。因此,color可能的值是red、orange、yellow等。这些符号常量被称为枚举符。
再看这个枚举:
enum DAY
{MON=1, TUE, WED, THU, FRI, SAT, SUN
};
第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。
枚举变量的定义
1、先定义枚举类型,再定义枚举变量
enum DAY
{MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY day;
2、定义枚举类型的同时定义枚举变量
enum DAY
{MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
3、省略枚举名称,直接定义枚举变量
enum
{MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
实例:
#include <stdio.h>enum DAY
{MON=1, TUE, WED, THU, FRI, SAT, SUN
};int main()
{enum DAY day;day = WED;printf("%d",day);return 0;
}
结果:3
在C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的,所以按照 C 语言规范是没有办法遍历枚举类型的。
不过在一些特殊的情况下,枚举类型必须连续是可以实现有条件的遍历。
以下实例使用 for 来遍历枚举的元素:
#include <stdio.h>enum DAY
{MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
int main()
{// 遍历枚举元素for (day = MON; day <= SUN; day++) {printf("枚举元素:%d \n", day);}
}
以上实例输出结果为:
枚举元素:1
枚举元素:2
枚举元素:3
枚举元素:4
枚举元素:5
枚举元素:6
枚举元素:7
以下枚举类型不连续,这种枚举无法遍历
enum
{ENUM_0,ENUM_10 = 10,ENUM_11
};
枚举在 switch 中的使用
#include <stdio.h>
#include <stdlib.h>
int main()
{enum color { red=1, green, blue };enum color favorite_color;/* 用户输入数字来选择颜色 */printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): ");scanf("%u", &favorite_color);/* 输出结果 */switch (favorite_color){case red:printf("你喜欢的颜色是红色");break;case green:printf("你喜欢的颜色是绿色");break;case blue:printf("你喜欢的颜色是蓝色");break;default:printf("你没有选择你喜欢的颜色");}return 0;
}
以上实例输出结果为:
请输入你喜欢的颜色: (1. red, 2. green, 3. blue): 1
你喜欢的颜色是红色
将整数转换为枚举
#include <stdio.h>
#include <stdlib.h>int main()
{enum day{saturday,sunday,monday,tuesday,wednesday,thursday,friday} workday;int a = 1;enum day weekend;weekend = ( enum day ) a; //类型转换//weekend = a; //错误printf("weekend:%d",weekend);return 0;
}
以上实例输出结果为:
weekend:1
了解一下
共享名称空间
C语言使用名称空间标识程序中的各部分,即通过名称来识别。作用域是名称空间概念的一部分:两个不同作用域的同名变量不冲突;两个相同作用域的同名变量冲突。名称空间是分类别的。在特定作用域中的结构标记、联合标记和枚举标记都共享相同的名称空间,该名称空间与普通变量使用的空间不同。这意味着在相同作用域中变量和标记的名称可以相同,不会引起冲突,但是不能在相同作用域中声明两个同名标签或同名变量。例如,在C中,下面的代码不会产生冲突:
struct rect { double x; double y; };
int rect; //在C中不会产生冲突
尽管如此,以两种不同的方式使用相同的标识会造成混乱。另外,C++中不允许这样做,因为它把标记名和变量名放在相同的名称空间中。