一、枚举
枚举是一种用户定义的数据类型,它用关键字enum以如下的语法来声明:

enum 枚举类型名字 {名字0,名字1,…,名字n};

(1)用枚举进行输入输出:

  • 当我们需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量值一些名字。

enum color {red,yellow,green};

enum color t = red;

  • 枚举类型可以加上enum作为类型。(实际上很少用)
  • void f(enum color c); //枚举量可以作为值。
  • 实际上,在C语言内部中,enum就是int,所以每个枚举类型的变量是可以像int一样进行输入与输出的。

    (2)自动计数的枚举:
    在枚举的定义当中,所有的名字的量是依次递增的,比如enum COLOR{RED,YELLOW,GREEN,NumCOLORS};RED是0,YELLOW是1,GREEN是2,所以跟在最后一个名字后面的量的值就是前面名字的计数,NumCOLORS是3。
    定义NumCOLORS来计数枚举类型中有多少个名字,那么就
    ①可以使用NumCOLORS来定义数组
    ②可以使用NumCOLORS来判断用户输入的数字是不是再有效的范围内
    ③可以将NumCOLORS放在for循环中进行遍历所有的枚举量。

(3)声明枚举量的时候可以指定值:

enum COLOR{RED=1,YELLOW,GREEN=5,NumCOLORS};

当RED定义为1的时候,YELLOW就是1+1=2,定义时也可以是离散的,GREEN=5,中间的没有3和4。此时的NumCOLORS就是6了,便不可以用来计数了。

(4)枚举只是int

  • 如果是用在有意义上排比的名字,用来定义符号量,用枚举比const int方便。
  • 枚举比宏(macro)好,因为枚举有类型而宏没有。

二、结构
一个结构就是一个复合的数据类型,里面有各种数据类型的成员,然后用一个变量来表达那么多的数据。
通常在函数外部声明结构类型。

(1)结构基本知识
1定义结构变量

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

声明了一个结构叫做point,定义了这种结构的两个变量p1和p2。

2结构变量的初始化:

struct date today = {02,9,2018};
//与数组类似。


3结构成员:
结构里有很多个成员,这些成员可以是不同类型,可以使用小圆点.运算符和成员名字来访问其成员,比如:

today.day; 访问today变量的成员
day p1.x; 访问结构变量p1的成员x

  • 结构类型是虚的,结构类型.xxx是没有意义的。
  • 结构变量才是实体,在.运算符左边的一定是一个结构变量。

4结构指针
结构变量的名字并不是结构变量的地址,必须使用&运算符。(而数组的名字就是数组的首地址)

struct date *p = &today; //指向结构的指针,&不能去掉。


5结构运算
要访问整个结构,直接用结构变量的名字。
对于整个结构,可以做赋值、取地址、也可以传递给函数参数。

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

赋值:
p=(struct point){ 5,10};//相当于强制转换为p.x=5,p.y=10。
p=p2;//相当于p.x=p2.x,p.y=p2.y;

(2)结构与函数
1.结构作为函数参数:

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

↓如例:写一程序根据输入的日期,输出第二天的日期。

#include<iostream>

using namespace std;

struct date{
	int month;
	int day;
	int year;
}today,tomorrow;

bool isleapyear(struct date n);
int numberofdays(struct date n);

int main()
{
	cout<<"请给定一个日期(mm dd yyyy):";
	cin>>today.month>>today.day>>today.year;
	if(today.day!=numberofdays(today))
	{
		tomorrow.day=today.day+1;
		tomorrow.month=today.month;
		tomorrow.year=today.year;
	}
	else if(today.month==12)
	{
		tomorrow.day=1;
		tomorrow.month=1;
		tomorrow.year=today.year+1;
	}
	else
	{
		tomorrow.day=1;
		tomorrow.month=today.month+1;
		tomorrow.year=today.year;
	}
	cout<<"第二天是"<<tomorrow.month<<'-'<<tomorrow.day<<'-'<<tomorrow.year<<endl;
	return 0;
}
bool isleapyear(struct date n)
{
	bool leap=false;
	if((n.year%4==0&&n.year%100!=0)||n.year%400==0)
		leap=true;
	return leap;
}
int numberofdays(struct date n)
{
	int days;
	const int dayspermonth[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
	if(n.month==2&&isleapyear(n))
		days=29; 
	else
		days=dayspermonth[n.month];
	return days;
}

运行代码:

2.输入结构:
没有一个直接的方式可以一次scanf一个结构,如果打算写一个函数来读入结构呢?


在getStruct函数中输入4和5之后,该函数内部输出4和5,但是回到main中,y的值依然是0和0.
因为C语言里在函数调用时是传值的。p和y并没有联系。这一点和数组不一样。所以上述代码是不能完成输入结构的。

解决方法一:将结构变量作为函数返回值

解决方法二:结构指针作为函数参数(更好):
在将一个结构传递给函数时,一般不传结构,而是传递结构的指针。
指向结构的指针:

struct date{
    int month;
    int day;
    int year;
} myday;

struct date *p = &myday;//做出一个结构指针指向结构变量myay 
 
(*p).month =12;   //①两种写法 
p->month =12;  //②一般说成p所指的(那个结构的)month

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

(3)结构中的数组
1.结构数组
输出一系列时间的后一分钟:

#include <stdio.h>

struct time 
{
    int hour;
    int minutes;
    int seconds;
}; 

struct time timeUpdate(struct time now);  //函数参数是struct time类型变量,返回值也是struct time类型 

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",testTimes[i].hour,testTimes[i].minutes,testTimes[i].seconds); 
        testTimes[i] = timeUpdate(testTimes[i]);//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)
{  //时间+1分钟 
    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;
            }
        }
    }
    return now;
}   

程序运行:

2结构中的结构:zzz
3结构中结构的数组:zzz

三、类型定义与联合
1.类型定义(typedef)
typedef的作用是声明一个数据类型的新名字,新名字相当于该数据类型的别名,改善了程序的可读性。

2.联合(union)
struct中的两个成员是分开的,是可以随意使用的。但是对于union来说,这两个成员占据了同一个空间。
联合在存储的时候,所有成员共享一个空间,同一时间只有一个成员是有效的。
union的空间是其最大成员的大小。对联合进行初始化的时候,只需对第一个成员做初始化。