枚举 (Enumer)

枚举是一种用户定义基本数据类型,使用关键字enum声明,主要用于排比一系列有意义的名字

格式

enum 枚举名 {枚举元素1,枚举元素2,...}

枚举元素只能是int类型,可以作为常量符号使用

枚举可以让独立定义的连续常量更简洁化

例如

1
2
3
4
const int zero = 0;
const int one = 1;
const int two = 2;
const int three = 3;

可以使用枚举写成enum number{zero,one,two,three}

第一个枚举元素默认从0开始,你可以指定第一个从任意数字开始,后面依次排列

输入输出

枚举的元素可以作为值去使用,而枚举类型可以带上enum作为数据类型,犹如int、double这种数据类型一样,还可以以整数的方式做内部计算和外部的输入输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

enum number { one = 1, two, three }; // 声明number类型的数据类型
void f(enum number x); // 声明f函数需要一个number类型的参数
int main() {
enum number t = 0; // 初始化number类型的临时变量t
scanf("%d" , &t);
f(t); // 传递t的值到f函数
return 0;
}
void f(enum number x){
printf("%d", x); // 输出number类型的x变量
return;
}

结构体 (Struct)

可以理解成可以存放不同数据类型的数组,一个结构中包含了多个成员的数据类型

⇩长代码警告!

结构类型

结构类型需要使用struct语句,定义变量时需要带上struct以及结构类型名称

格式
1
2
3
4
5
6
// 声明结构
struct 结构体类型名称 {
成员变量;
};
// 定义变量
struct 结构体类型名称 变量名;

也可以写成下面这样,它们的意思是一样的

1
2
3
4
// 声明结构并定义变量
struct 结构体类型名称 {
成员变量;
}变量名;

每个变量名都包含结构变量的所有内容,当你要对变量赋值时,需要对应结构体中的成员变量类型

结构运算

与数组一样,当需要访问结构成员时,使用变量名 .成员变量的方式

要访问整个结构的时候直接用结构变量的名称就行

对于整个结构,可以做赋值,取地址的操作,还可以传递给函数参数

初始化

在定义变量的时候就初始化结构内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

// 声明结构并定义变量
struct number {
int one;
int two;
int three;
} demo;

int main() {
// 初始化变量struct number类型的变量demo的值为one = 10,two = 20,three = 30
struct number demo = {10, 20, 30};
printf("one = %i,two = %i, three = %i", demo.one, demo.two, demo.three);
// one = 10,two = 20, three = 30
return 0;
}

还可以用另一种方式去初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

// 声明结构并定义变量
struct number {
int one;
int two;
int three;
}demo;

int main() {
// 初始化变量struct number类型的变量demo的值为one = 10,two = 20,three = 30
demo = (struct number){10, 20, 30};
printf("one = %i,two = %i, three = %i", demo.one, demo.two, demo.three);
// one = 10,two = 20, three = 30
return 0;
}

甚至你还可以像数组一样对单个成员变量初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
// 声明结构并定义变量
struct number {
int one;
int two;
int three;
}demo;
int main() {
// 初始化变量struct number类型的变量demo的值为one = 10,three = 30,而没有给值的two默认为0
demo = (struct number){.one = 10, .three = 30};
printf("one = %i,two = %i, three = %i"
, demo.one, demo.two, demo.three);
// one = 10,two = 0, three = 30
return 0;
}
结构指针

与数组不同的是,结构变量的名称并不是结构变量的地址,所以在访问结构变量在内存中的的地址时,需要用到取地址符&

1
2
struct number *p = &demo;
printf("demo = %p", p); // demo = 0x10c62b010

需要用指针指向结构内容时,可以用到一个新的运算符->

意为将指针指向结构的成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

// 声明结构并定义变量
struct number {
int two;
}demo;

int main() {
// 初始化变量struct number类型的变量demo的值为two = 20
demo = (struct number){ 20 };
printf("two = %i\n", demo.two); // two = 20
struct number *p = &demo; // 让指针p指向结构变量demo的地址
// 使用指针p去修改结构成员的值
p -> two = 200; // == demo.two = 200; == (*p).two = 200 ;
printf("two = %i", p->two);

return 0;
}

学生表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
struct student {
int studentID;
char *name;
char *sex;
int age;
}first;

int main() {
//struct student first;
first = (struct student)
{1003,"张三","男",19};
printf("名字\t性别\t年龄\t学号\t\n%s\t%s\t%i\t%i"
,first.name, first.sex, first.age, first.studentID);
return 0;
}

结构函数

整个结构可以作为参数的值传入函数

当传递的是一个结构时,在函数中是新建了一个结构变量,并复制了调用者的结构的值

这个函数的返回类型可以是一个结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*
* 判断是否为闰年,如果是闰年让今年的2月变成29天
* 明天的日期根据用户输入的值去改变*/
#include <stdio.h>
#include <stdbool.h>


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

int numberofDays(struct date d);

bool isLeap(struct date d);

int main() {
struct date today, tomorrow;
printf("Enter today's date (mm-dd-yy):");
scanf("%i-%i-%i", &today.month, &today.day, &today.year);
// 当今天的日期不等于num函数返回的结果时
if (today.day != numberofDays(today)) { // num函数调用主函数中的结构变量today
// 明天的日期就+1,月和年保持不变
tomorrow.day = today.day + 1;
tomorrow.month = today.month;
tomorrow.year = today.year;
} else if (today.month == 12) {
// 当今年的月份是十二月并且不满足上个if时
// 明天的日期变成1,月份变成1,年份加一
tomorrow.day = 1;
tomorrow.month = 1;
tomorrow.year = today.year + 1;
} else {
// 综上条件都不满足,即在月末的最后一天
// 明天的日期变成1,月份加一,年份不变
tomorrow.day = 1;
tomorrow.month = today.month + 1;
tomorrow.year = today.year;
}
printf("Tomorrow'date is %i-%i-%i",
tomorrow.month, tomorrow.day, tomorrow.year);
return 0;
}

/*
* NumberOfDays函数的目的是算出月末的最后一天*/
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)) { // 如果这个月是2月份,并且isLeap函数返回的是true
days = 29; // 就让days变成29
} else {
days = dayspermonth[d.month - 1]; // 如果不是2月份就让days变成数组中与月份对应的日子
}
return days;
}

/*
* isLeap函数的作用是判断是否是闰年
* 返回值默认是false,如果是闰年就返回true*/
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;
}

结构数组

声明结构数组:struct 结构体类型名称 成员变量[数组元素个数]例如

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 time {
int hour;
int min;
int seconds;
}NowTime;

int main() {
struct time NowTime[5] = {
// NowTime[0] = ((NowTime.hour = 11),(NowTime.min = 59),(NowTime.seconds = 59))
{11,59,59},
// NowTime[1] = ((NowTime.hour = 12),(NowTime.min = 0),(NowTime.seconds = 0))
{12,0,0},
// ...以此类推
{1,59,29},
{23,59,59},
{19,50,29}
};
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
* 定义一个结构数组,分别存放小时分钟秒
* 遍历数组,输出每一个数组元素
* 定义第二个函数,作用是算出当前时间的下一秒的时间*/
#include <stdio.h>

// 声明结构
struct time {
int hour;
int min;
int seconds;
} NowTime;

// 声明函数
struct time LaterTime(struct time now);

int main() {
// 常量CURT的值是5
const int CURT = 5;
// 初始化结构数组
struct time NowTime[CURT] = {
// NowTime[0] = ((NowTime.hour = 11),(NowTime.min = 59),(NowTime.seconds = 59))
{11, 59, 59},
{12, 0, 0},
{1, 59, 29},
{23, 59, 59},
{19, 50, 29}
};
struct time *p = NowTime; // 定义struct time类型的指针变量p
for (int i = 0; i < CURT; i++) {
*p = NowTime[i]; // 让指针变量p指向结构数组NowTime,每轮循环让NowTime[0+i]
printf("Nowtime is %.2i:%.2i:%.2i",
p->hour, p->min, p->seconds); // 指针变量p指向每个结构成员
*p = LaterTime(*p); // 让指针变量p指向函数LaterTime,参数是NowTime[0+i]
printf("...One seconds later its %.2i:%.2i:%.2i\n",
p->hour, p->min, p->seconds);
}
return 0;
}

struct time LaterTime(struct time now) {
++now.seconds;
if (now.seconds == 60) {
now.seconds = 0;
++now.min;
if (now.min == 60) {
now.min = 0;
++now.hour;
if (now.hour == 24) {
now.hour = 0;
}
}
}
return now;
}

嵌套结构(禁止套娃!)

既然结构内可以是不同类型的数据,那么也可以是结构类型的数据

1
2
3
4
struct aAndb{
struct a dataa;
struct b datab;
};

空间想象力太差了,告辞

复用的时候看作文件夹与快捷键就行

06-10_22:25

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>

struct point {
int x;
int y;
};

struct rectangle {
struct point p1;
struct point p2;
};

void printRect(struct rectangle r) {
printf("<%d,%d> to <%d,%d>\n",
r.p1.x, r.p1.y, r.p2.x, r.p2.y);
}

int main() {
struct rectangle rects[] = {
/*
* rects[0] r.p1.x = 1,r.p1.y = 2
* rects[0] r.p2.x = 3,r.p2.y = 4
* rects[1] r.p1.x = 5,r.p1.y = 6
* rects[1] r.p2.x = 7,r.p2.y = 8 */

{{1, 2}, {3, 4}},
{{5, 6}, {7, 8}}
};
for (int i = 0; i < 2; i++) {
printRect(rects[i]);
}
return 0;
}

TypeDef

使用typedef可以自定义数据类型的名称,让其变成新的别名

复杂的名字化繁为简,重载已有的类型名称,新名称的含义更清晰更具有移植性

还能够替代数据类型出现在变量定于和参数声明

使用typedef最后的单词就是该类型的新名称

1
2
3
typedef int abc; // 将int类型定义别名为abc
abc a,b,c; // 等价于int a,b,c
abc number[5]; // 等价于int number[5]
1
2
3
4
5
6
7
typedef struct student {
int studentID;
char *name;
char *sex;
int age;
}aaa;
aaa zhangsan = {111,"zhangsan","nan",17};

union(联合)

联合是一种特殊的数据类型,允许在相同的内存位置存储不同的数据类型

可以定义一个带有多成员的联合体,但是任何时候只能有一个成员带有值,联合体提供了一种使用相同的内存位置的有效方式

它的语法和结构一样,但是每个成员是共享一个空间

而且同一时间只有一个成员是有效的,union整体的空间大小就是最大的那个成员

所以你不能同时输出联合体中的所有成员的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <string.h>

union Data {
int i;
float f;
char str[20];
};

int main() {
union Data data;

data.i = 10;
printf("data.i : %d\n", data.i);

data.f = 220.5;
printf("data.f : %f\n", data.f);

strcpy(data.str, "Hello,World");
printf("data.str : %s\n", data.str);

return 0;
}

评论