C语言学习之十——共用体、枚举类型和typedef

  1. 共用体
    1.1共用体的概念 :使几个不同的变量共占同一段内存的结构,称为“共用体”类型的结构。
    1.2 定义共用体类型变量的一般形式为:
    union 共用体名
    {
    成员表列
    }变量表列;

其实定义共用体变量有3中方法,其方法与定义结构体变量的3种方法类似:
1) 先声明共用体类型再定义变量名

union date
{
int year;
int month;
long day;
};
union date d1, d2;

2)在定义结构体类型的同时定义变量
union 共用体名
{
成员列表
}变量名列表;

例:
union date
{
int year;
int month;
long day;
}d1, d2;

3) 直接定义共用体类型变量
union
{
成员列表
}变量名列表;

例:
union
{
int year;
int month;
long day;
}d1, d2;

1.3 共用体与结构体的比较
结构体变量所占内存长度是各成员占的内存长度之和,因为每个成员分别占有其自己的内存单元。共用体变量所占的内存长度等于最长的成员的长度,因为所用成员共享一个公共的内存单元,所以需要满足最长成员的长度。见例1.

例如 : 上面定义的“共用体”变量d1、d2各占8个字节(因为在GCC中一个整型变量占4个字节,一个长整形变量占8个字节),而不是各占 4 +4+8=16个字节。

1.4 共用体变量的引用方式
只有先定义了共用体变量才能引用它,而且不能引用共用体变量,而只能引用共用体变量中的成员。
例如 : 前面定义了d1, d2为共用体变量
d1.year (引用共用体变量d1中的整型变量year)
d1.month(引用共用体变量d1中的字符变量month )
d1.day(引用共用体变量d1中的长整型变量day)

1.5 共用体类型数据的特点
1)同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一种,而不是同时存放几种。
2)共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员就失去作用。
3)共用体变量的地址和它的各成员的地址都是同一地址。
(这3条特点共同说明了,所用共用体成员共享一个公共的内存单元)见例1.
4)不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,又不能在定义共用体变量时对它初始化。

5)不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针。
6)共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。见例2.

//例1.
/#include<stdio.h>

union date
{
int year;
int month;
long day;
}d1, d2;

void main()
{
d1.year = 2018;
d1.month = 01;
d1.day = 01;

printf("%d-%d-%ld\n", d1.year, d1.month, d1.day);
printf("&d1.year: %o, &d1.month: %o, &d1.day: %o\n", &d1.year, &d1.month, &d1.day);
printf("sizeof(d1): %d\n", sizeof(d1));

d1.year = 2018;
d1.month = 01;
d1.day = 02;

printf("%d-%d-%ld\n", d1.year, d1.month, d1.day);
printf("&d2.year: %o, &d2.month: %o, &d2.day: %o\n", &d2.year, &d2.month, &d2.day);
printf("sizeof(union date): %d\n", sizeof(union date));
}
//输出:
1-1-1
&d1.year: 30010100, &d1.month: 30010100, &d1.day: 30010100
sizeof(d1): 8

2-2-2
&d2.year: 30010110, &d2.month: 30010110, &d2.day: 30010110
sizeof(union date): 8

//例2
/#include <stdio.h>

struct
{
int num;
char name[10];
char sex;
char job;
union
{
int banji;
char position[10];
}category;
}person[2]; //为了方便先假设一个学生一个老师。

void main()
{
int i;
for(i=0; i < 2; i++)
{
printf("Please input the num: ");
scanf("%d", &person[i].num);
printf("Please input the name: ");
scanf("%s", person[i].name);
fflush(stdin);
printf("Please input the sex(M/F): ");
scanf("%c", &person[i].sex);
fflush(stdin);
printf("Please input the job(s/t): ");
scanf("%c", &person[i].job);
fflush(stdin);
if( person[i].job == 's' )
{
printf("Please input the class: ");
scanf("%d", &person[i].category.banji);
fflush(stdin);
}
else if( person[i].job == 't' )
{
printf("Please input the position: ");
scanf("%s", person[i].category.position);
fflush(stdin);
}
else
{
printf("Input Error!!\n");
}
printf("\n");
}
printf("No. name sex job class/position\n");
for( i=0; i < 2; i++ )
{
if( person[i].job == 's')
{
printf("%-6d%-10s%-3c%-3c%10d\n", person[i].num,
person[i].name, person[i].sex, person[i].job,
person[i].category.banji);
}
else
{
printf("%-6d%-10s%-3c%-3c%10s\n", person[i].num,
person[i].name, person[i].sex, person[i].job,
person[i].category.position);
}
}
}

  1. 枚举类型
    2.1 概念:在实际问题中,有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等。如果把这些量说明为整型,字符型或其它类型显然是不妥当的。为此,C语言提供了一种称为“枚举”的类型。
    2.2 枚举变量的声明:设有变量 a,b,c 被说明为上述的 weekday ,可采
    用下述任一种方式:
    1)enum weekday{ sun,mou,tue,wed,thu,fri,sat };
    enum weekday a, b, c;

2)enum weekday{ sun,mou,tue,wed,thu,fri,sat }a, b, c;

3)enum { sun,mou,tue,wed,thu,fri,sat }a, b, c;

2.3 注意事项:
1)在“枚举”类型的定义中列举出所有可能的取值,被说明为该“枚举”类型的变量取值不能超过定义的范围。
2)枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型。
3)在枚举值表中应罗列出所有可用值。这些值也称为枚举元素。
4)在C编译中,对枚举元素按常量处理,故称枚举常量。它们不是变量,不能对它们赋值。
5)枚举元素作为常量,它们是有值的,C语言编译按定义时的顺序使它们的值为0,1,2...
6)枚举值可以用来作判断比较。
7)一个整数不能直接赋给一个枚举变量。

//例3
/#include <stdio.h>

void main()
{
enum weekday{sun, mon, tue, wed, thu, fri, sat}a, b, c; /定义枚举类型weekday,并声明枚举变量a, b, c/
a = 1; // a = 1;这样是不行的,因为这里是用一个整形的1来覆盖a所代表的 enum
b = mon;
c = sat;
printf("%d, %d, %d", a, b, c);
printf("\n\n");
}
//输出: 1, 1, 6

//例4
/#include <stdio.h>

void main()
{
enum boy{Tom, Danny, Gan, LiLei}month[31], j;
int i;
j = Tom;
for( i=1; i <= 30; i++ )
{
month[i] = j;
j++;
if( j > LiLei )
{
j = Tom;
}
}
for( i=1; i <= 30; i++)
{
switch( month[i] )
{
case Tom: printf(" %4d %s\t", i, "Tom");
break;
case Danny: printf(" %4d %s\t", i, "Danny");
break;
case Gan: printf(" %4d %s\t", i, "Gan");
break;
case LiLei: printf(" %4d %s\t", i, "LiLei");
break;
default:
break;
}
}
printf("\n");
}
//输出:
1 Tom 2 Danny 3 Gan 4 LiLei 5 Tom
6 Danny 7 Gan 8 LiLei 9 Tom 10 Danny
11 Gan 12 LiLei 13 Tom 14 Danny 15 Gan
16 LiLei 17 Tom 18 Danny 19 Gan 20 LiLei
21 Tom 22 Danny 23 Gan 24 LiLei 25 Tom
26 Danny 27 Gan 28 LiLei 29 Tom 30 Danny

  1. typedef
    3.1 typedef的作用:用 typedef 声明新的类型名来代替已有的类型名
    3.2 用 typedef 定义类型
    1)声明 INTEGER 为整型:“typedef int INTEGER;” 见例5

//例5
/#include <stdio.h>
typedef int INTEGER;

void main()
{
INTEGER i = 1;
int j = 2;
printf("%d, %d\n", i, j);
}
//输出:1, 2

2)声明结构类型

Typedef struct
{
int month ;
int day ;
int year ;
}DATE;

//例6
/#include <stdio.h>
typedef struct
{
int month;
int day;
int year;
}DATE;
void main()
{
DATE date_one;
date_one.month = 12;
date_one.day = 31;
date_one.year = 2017;
printf("%d - %d - %d \n", date_one.year, date_one.month, date_one.day);
}
//输出: 2017-12-31

3)声明NUM为整型数组类型:“typedef int NUM[100];” 见例7.

//例7
/#include <stdio.h>

typedef int NUM[100];

void main()
{
NUM num = {0};
printf("%d\n", sizeof(num));
}
//输出:400

4)声明STRING为字符指针类型:“typedef char* STRING ;”见例8.

//例8.
/#include <stdio.h>

typedef char* P; //声明字符指针类型P

void main()
{
P p1;
p1 = "I love UNSW";
printf("%s\n", p1);
}
//输出: I love UNSW

5)声明P为函数指针类型:“typedef void (*P)();”见例9

//例9
/#include <stdio.h>

typedef void (*P)(); //声明函数指针类型P

void fun();
void main()
{
P p1; // 这里的p1等价于“void (*p1)();”即定义p1为函数指针类型P的实参
p1 = fun; //将函数fun()的入口地址赋给指针变量p1
( * p1)(); //函数指针通过调用函数实现输出
}

void fun()
{
printf("I love UNSW\n");
}
//输出:I love UNSW

3.3 用 typedef 定义类型的方法
1)按定义变量的方法写出定义体(如: int i )
2)将变量名换成新类型名(例如:将 i 换成 COUNT )。
3)在最前面加typedef (例如: typedef int COUNT )
4)然后可以用新类型名去定义变量(例如: COUNT i,j;)

3.2 关于typedef的说明
1)用 typedef 可以声明各种类型名,但不能用来定义变量。
2)用 typedef 只是对已经存在的类型增加一个类型名,而没有创造新的类型。
3)当不同源文件中用到同一类型数据时,常用 typedef 声明一些数据类型,把它们单独放在一个文件中,然后在需要用到它们的文件中用 #include命令把它们包含进来。
4)使用 typedef 有利于程序的通用与移植。

3.1 typedef 与 #define 的比较
相似:typedef 与 #define 有相似之处,例如: typedef int COUNT ; #define COUNT int 的作用都是用 COUNT 代表 int 。

区别:#define 是在预编译时处理的,它只能作简单的字符串替换,而 typedef 是在编译时处理的。实际上它并不是作简单的字符串替换,而是采用如同定义变量的方法那样来声明一个类型。
另外注意,“typedef (int * ) p1;”和“#define p2 int*” 一个有分号,一个没有分号

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容