结构类型

枚举

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

1
enum name{name1,name2,...,namen}

枚举类型名字通常不怎么使用,要用的是大括号里的名字,这些常量符号类型为int,默认值依次为0到n,即name1为0,name2为1,最后一个常量的值也是常量的个数,也可以在声明枚举量时指定值

1
enum name{name1=3,name2,name3=5}

当需要一些可以排列起来的常量值时,定义枚举可以实现,在switch-case语句中可以用常量符号代替数字,如case name1: …;等,比定义独立的const int变量更好用

枚举类型是以整数做内部计算和外部输入输出的,枚举只是int,赋给枚举变量1~n以外的整数也不会有任何warning和error

结构

声明结构类型的三种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct name{
int a;
int b;
};
struct name pl,p2;
//p1 和 p2 都是point⾥⾯有x和y的值

struct{
int a;
int b;
}p1,p2;
//p1 和 p2都是⼀种⽆名结构,⾥⾯有x和y

struct name{
int a;
int b;
}
//p1,p2;p1和p2都是point⾥⾯有x和y的值t

对于第⼀和第三种形式,都声明了结构point,但是第⼆种形式没有声明point,只是定义了两个变量,下面是一个用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
struct x{
int a;
int b;//通常在函数外部声明结构类型,这样就可以被多个函数所使⽤了
}p1,p2;
int main()
{
struct x y;
y.a=1;
y.b=2;
printf("%d,%d",y.a,y.b);//也可以用%i,在printf中二者效果一样,scanf则分进制
return 0;
}

结构的初始化

1
2
3
4
5
6
7
8
...
int main()
{
struct x y={1,2};
struct x k={.a=1};
printf("%d,%d",y.a,y.b);
return 0;
}

两种初始化方式,可以仅指定某些成员初始化

结构运算

要访问整个结构,直接⽤结构变量的名字

对于整个结构,可以做赋值、取地址,也可以传递给函数参数

1
2
3
p1 = (struct name){5, 10}; // 相当于p1.x = 5; p1.y = 10;
p1 = p2;// 相当于p1.x = p2.x; p1.y = p2.y;
//(数组不能做这两种运算)

结构指针

1
struct date *pDate = &today;

必须需用&,结构变量的名字不是地址,和数组区分开

结构与函数

1
int day(struct name a)

整个结构可以作为参数的值传⼊函数,这时候是在函数内新建⼀个结构变量,并复制调⽤者的结构的值,这样的函数也可以返回⼀个结构

输入结构并返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdio.h>
struct name{
int a;
int b;
};
void getstruct(struct name);
void outstruct(struct name);
void main()
{
struct name y={0,0};
getstruct(y);
outstruct(y);
}
void getstruct(struct name p){
scanf("%d",&p.a);
scanf("%d",&p.b);
printf("%d,%d",p.a,p.b);
}
void outstruct(struct name p){
printf("%d,%d",p.a,p.b);
}

向函数提供一个结构y,函数会在内部新建⼀个结构变量p,读入输入的结构,我们比较一下getstruct(y)和outstruct(y)打印的结构是否与输入的结构相同,显然,outstruct仍然是0,0;main()中的y没有变,也就是说输入的结构没有返回,那么如何返回呢?

解决方式有以下几种:

1.在函数中创建一个临时结构变量读入结构并返回,即return+临时结构名;

2.将y的地址传给函数,也就是结构指针;

指向结构的指针

1
2
3
4
5
6
7
struct date{
int year;
int month;
}day;
struct date *p=&day;
(*p).month=12;
p->month=12;//两种表述都可以,一般⽤->表⽰指针所指的结构变量中的成员

结构指针作为参数

这会比创建一个临时结构好得多

1
2
3
4
5
6
7
8
9
10
11
12
13
void main() 
{
struct point y = {0, 0};
inputPoint(&y);
output(y);
}

struct point* inputPoint(struct point *p)
{
scanf(“%d”,&(p->x));
scanf(“%d”,&(p->y));
return p;
}

好处是传入传出只是⼀个指针的大小,返回传⼊的指针是⼀种套路

如果需要保护传入的结构不被函数修改我们可以const struct point *p

结构中的结构

1
2
3
4
struct dateAndTime {
struct date sdate;
struct time stime;
};

访问成员时用多个.就可以了,如school.class.student1

如果有变量定义:

1
2
struct rectangle r,*rp;
rp = &r;

那么下面的四种形式是等价的:

1
2
3
4
r.pt1.x 
rp->pt1.x
(r.pt1).x
(rp->pt1).x

结构数组

1
2
3
struct date dates[100];
struct date dates[] = {
{4,5,2005},{2,4,2005}};

每一个成员都要用大括号括起来