[C语言]枚举、struct结构、typedef和union

一、枚举

1、基本概念

枚举是一种用户定义的数据类型,它用关键字enum以如下语法来声明
enum 枚举类型名字{名字0,…,名字n};
枚举类型的名字通常并不真的使用,要用的是在大括号里的名字,因为它们就是常量符号,他们的类型是int,

值则依次从0到n。如:
enum peoples{ Leo,Tim,Tom,Ann};
创建了三个常量,Leo的值是0,Tim是1,而Ann是2.
需要一些可以排列起来的常量值时,定义枚举的意义就是给这些常量值名字。

枚举量可以做值
枚举类型可以跟上enum作为类型
但是实际是以整数来做内部计算和外部输入输出的
声明枚举量的时候可以指定值
enum COLOR {RED=1, YELLOW, GREEN=5};
即使给枚举类型的变量赋不存在的整数值也没有任何warning或error

tips
虽然枚举类型可以当作类型使用,但是实际上很少用
如果有意义上排比的名字,用枚举比const int方便
枚举比宏(macro)好,因为枚举有int类型

2、枚举的简单应用

#include <stdio.h>

enum COLOR {RED, YELLOW, GREEN, NumCOLORS};		//枚举三种颜色

int main(int argc, char const *argv[])
{
	int color = -1;		//定义判断值
	char *colorName = NULL;
	
	printf("请输入你喜欢的颜色的代码:");
	scanf("%d", &color);		//读入颜色代码
	switch( color ) {
	case RED: colorName = "red"; 
	break;
	case YELLOW: colorName = "yellow"; 
	break;
	case GREEN: colorName = "green"; 
	break;
	default: colorName = "unknown"; 
	break;
	}		//根据输入的不同输出
	printf("你喜欢的颜色是%s\n", colorName);		//输出最喜欢的颜色
	
	return 0;
}

二、结构

1、struct结构

声明结构类型
和本地变量一样,在函数内部说明的结构类型只能在函数内部使用。
所以通常在函数内外说明结构类型,这样就可以被多个函数所使用了。

struct point{
int x;
int y;
};

srtuct point p1, p2;
p1和p2都是point里面x和y的值

struct{
int x;
int y;
} p1, p2;

p1和p2都是一种无名结构,里面有x和y

struct point{
int x;
int y;
}p1, p2;

p1和p2都是point里面有x和y的值t。

对于第一和第三种形式都声明了结构point但是第二种结构没有声明point,只定义的两种两个变量。

结构成员
结构和数组相似
数组用[]运算符和下标访问其成员
a[0] = 10;
结构用.运算符和名字访问其成员
today.day
student.firstName
p1.x
p1,y

结构运算
要访问整个结构,直接用变量的名字
对于整个结构可以做赋值,取地址,也可以传递给函数参数
p1 = (struct point){5, 10}; //相当于p1.x = 5; p1.y = 10;
p1 = p2; //相当于p1.x = p2.x; p1.y = p2.y;

结构指针
和数组不同,结构类型的名字必须是结构变量的地址,必须用&运算符
struct date *pDate = &today;

读入日期

#include <stdio.h>

struct date {		//定义结构
	int month;
	int day;
	int year;
};

int main(int argc, char const *argv[])
{
	struct date today;
	
	today.month = 11;		
	today.day = 4;
	today.year = 2022;		
	
	printf("Today`s date is %i-%i-%i.\n",today.year, today.month, today.day);
	
	return 0;
}

2、struct与函数

结构作为函数参数
整个结构也可以作为参数的值传入函数
这时候是在函数内新建一个结构变量,并复制调用者的结构的值
也可以返回一个结构
这与数组不同

输入结构
没有可以一次scanf一个结构

解决的方案
之前的方案把一个结构传入的函数,然后在函数中操作,但是没有返回回去。
问题在于传入函数的是外面的那个结构的克隆体而不是指针
传入结构和传入数组不同的
在这个输入函数中,完全可以创建一个临时的结构变量,然后把这个结构返回给调用者

指向结构的指针
用->表示指针所指的结构变量中的成员

结构数组
struct date dates[];
struct date dates[] = {
{4, 5, 2005}, {2, 4, 2004} };

简单应用(下一天)

#include <stdio.h>
#include <stdbool.h>

struct date {		//定义结构
	int month;
	int day;
	int year;
};

bool isLeap(struct date d);
int numberOfDays(struct date d);

int main(int argc, char const *argv[])
{
	struct date today, tomorrow;
	
	printf("Enter today's date (mm dd yyyy):");		
	scanf("%i %i %i", &today.month, &today.day, &today.year);		//读入date
	
	if( today.day != numberOfDays(today) ) {		//判断一般情况
		tomorrow.day = today.day+1;
		tomorrow.month = today.month;
		tomorrow.year = today.year;
	} else if (today.month == 12 ) {		//date为每年最后一天
		tomorrow.day = 1;
		tomorrow.month = 1;
		tomorrow.year = today.year + 1;
	} else {		//date为每月最后一天(不包括12月)
		tomorrow.day = 1;
		tomorrow.month = today.month+1;
		tomorrow.year = today.year;
	}
	
	printf("Tomorrow's date is %i-%i-%i.\n", tomorrow.year, tomorrow.month, tomorrow.day);
	
	return 0;
}

int numberOfDays(struct date d)
{
	int days;
	//列出每月的天数
	const int daysPerMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};			
	
	if ( d.month ==2 && isLeap(d) )		//闰年则为29天
	{
		days = 29;
	}else
	{
		days = daysPerMonth[d.month-1];
	}
	
	return days;	
}

bool isLeap(struct date d)		//判断平年和闰年
{
	bool leap = false;
	
	if( (d.year %4 == 0 && d.year %100 !=0 ) || d.year%400 == 0 )
		leap = true;
	
	return leap;
}


3、结构里的结构

嵌套的结构
struct point {
int x;
int y;
};

如果有变量
struct rectangle r;
就可以有
r.pt1.x 、r.pt1.y,
r.pt2.x和r.pt2.y

如果有变量定义
struct rectangle r, *rp;
rp = &r;
那么下面的四种形式是等价的:
r.pt1.x
rp->pt1.x
(r.pt1).x
(rp->pt1).x
但是没有rp->pt1->x (因为pt1不是指针)

简单应用(下一秒)

#include <stdio.h>

struct time{		//定义结构
	int hour;
	int minutes;
	int seconds;
};
 
 struct time timeUpdate(struct time now);
 
 int main(void)
 {
 	struct time testTimes[5] = {
 		{11, 59, 59}, {12, 0, 0}, {1, 29, 59}, {23, 59, 59}	, {19, 12, 27}	 
	 };			//读入代表时间的结构数组
	 int i;
	 
	 for ( i=0; i<5; ++i ) {
	 	printf("Time is %.2i:%.2i:%.2i\n", testTimes[i].hour, testTimes[i].minutes, testTimes[i].seconds );		
	 	
	 	testTimes[i] = timeUpdate(testTimes[i]);
	 	
	 	printf("...one second later it's %.2i:%.2i:%.2i\n", testTimes[i].hour, testTimes[i].minutes, testTimes[i].seconds);
	 }
	 
	 return 0;
 }
 
struct time timeUpdate(struct time now)
{
	++now.seconds;
	if ( now.seconds == 60 ) {
		now.seconds = 0;
		++now.minutes;
		
		if ( now.minutes == 60 ) {
			now.minutes = 0;
			++now.hour;
			
			if ( now.hour == 24 ) {
				now.hour = 0;
			}
		}
	}		//嵌套if,判断时间的特殊情况
	
	return now;
}
 
 

三、typedef和union

1、typedef

自定义数据类型(typedef)
C语言提供了一个叫做typedef 的功能,声明一个已有的数据类型的新名字。比如:
typedef int Length;
使得Length成为int类型得别名。
这样,Length这个名字就可以代替int出现在变量定义和参数声明的地方了

Length a, b, len ;
Length number[10];

Typedef
声明新的类型的名字
新的名字是某种类型的别名
改善了程序的可读性

typedef long int64_t;
typedef struct Adate {
int month;
int day;
int year;
} Date;

int64_t i = 10000000;
Date d = { 6, 11, 2022};

2、联合(union)

union AnElt {
int i;
char c;
} elt1, elt2;

elt1, elt2;

联合
存储
所有的成员共用一个空间
同一个时间只有一个成员是有效的
union 的大小是最大的成员

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值