博主不定期更新【保研/推免、C/C++、5G移动通信、Linux、生活随笔】系列文章,喜欢的朋友【点赞+关注】支持一下吧!
Lecture 6 结构类型
1. 枚举
- 常量符号化
用符号而不是具体的数字来代表程序中的数字; - 用枚举而不是定义独立的const int变量
枚举是一种用户定义的数据类型,它用关键字enum以如下语法来声明:
enum 枚举类型名字 {名字0,...,名字n};
枚举类型名字通常并不真的使用,要用的是在大括号里的名字,因为它们就是常量符号,它们的类型是int,值则依次从0到n。如:
enum colors {red,yellow,green}
就创建了三个常量,red的值是0,yellow是1,而green是2.
当需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量值名字。
套路:自动计数的枚举
enum colors {red,yellow,green,Numofcolors}
Numofcolors
值为3即为前面提到的颜色的总数目,这样需要遍历所有的枚举量或者需要建立一个用枚举量做下标的数组时就很方便。
声明枚举量的时候可以指定值
enum color {red=1,yellow,green=5} // 1,2,5
enum color COLOR=0;//即使给枚举类型的变量赋不存在的整数值也没有warning或error
- 虽然枚举类型可以当做类型使用,但是实际上很少用
- 如果有意义上排比的名字,用枚举比const int方便
- 枚举比宏(macro)好,因为枚举有int型
2. 结构
2.1 结构类型
声明结构类型:
#include <stdio.h>
int main()
{
struct date{ //声明一种新的结构类型
int month;
int day;
int year;
}; //分号别忘
struct date today;//定义一个结构变量today,其类型为struct date
today.month = 07;
today.day = 31;
today.year = 2014;
printf("Today's date is %i-%i-%i.\n", today.year, today.month, today.day);
return 0;
}
- 和本地变量一样,在函数内部声明的结构类型只能在函数内部使用
- 所以通常在函数外部声明结构类型,这样就可以被多个函数所使用
声明结构的形式:
形式一:
struct point {
int x;
int y;
};
struct 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的值
结构变量的初始化:
struct date today = {07,31,2014};
struct date thismonth = {.month=7, .year=2014};//没赋值默认为0即day=0
结构成员:
- 结构和数组有点像
- 数组用[]运算符和下标访问其成员
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;
2.2 结构与函数
结构作为函数参数
int numberofDays(struct date d)
- 整个结构可以作为参数的值传入函数
- 这时候是在函数内新建一个结构变量,并复制调用者的结构的值
- 也可以返回一个结构
- 这与数组完全不同
输入结构
- 没有直接的方式一次
scanf
一个结构
解决方案
- 在这个输入函数中,完全可以创建一个临时的结构变量,然后再把这个结构返回给调用者,之后可以通过赋值在主函数中进行运算;
输入结构 方式1:
struct point getStruct(void)
{
struct point p;
scanf("%d", &p.x);
scanf("%d", &p.y);
return p;
}
- 结构指针作为参数(更常用)
首先看看指向结构的指针:
struct date{
int month;
int day;
int year;
}myday;
struct date *p = &myday;
(*p).month = 12;
p->month = 12; //用->表示指针所指的结构变量中的成员
输入结构 方式2:
struct point* getStruct(struct point* p)
{
struct point p;
scanf("%d", &p->x);
scanf("%d", &p->y);
return p;
}
2.3 结构中的结构
结构数组:
struct date dates[100];
struct date dates[]={
{4,5,2005},{2,4,2005}
};
结构中的结构:
struct point{
int x;
int y;
};
struct rectangle{
struct point pt1;
struct point pt2;
};
如果有变量定义:
struct rectangle r, *rp;
rp = &r;
那么下面四种形式等价:
r.pt1.x
rp->pt1.x
(r.pt1).x
(rp->pt1).x
但是没有rp->pt1->x (因为pt1不是指针)
3. 联合
3.1 类型定义
如何摆脱struct
自定义数据类型(typedef)
- C语言提供了一个叫做
typedef
的功能来声明一个已有的数据类型的新名字,例如typedef int Length;
使得Length
成为int
类型的别名。这样,Length
这个名字就可以代替int出现在变量定义和参数声明的地方了,例如Length a,b,len; Length numbers[10];
Typedef:声明新的类型的名字
typedef long int64_t; //重载已有的类型名字,新名字的含义更清晰,具有可移植性
typedef struct ADate{
int month;
int day;
int year;
} Date; //简化了复杂的名字
int 64_t i = 100000000000;
Date d = {9, 1, 2005}; //此处Date相当于struct ADate
有了typedef,便可以:
typedef struct{ //此处不关心该结构的名字
int month;
int day;
int year;
} Date; //定义一个无名结构,之后命名为Date
3.2 联合
- 存储:所有的成员共享一个空间;同一时间只有一个成员是有效的;union的大小是其最大的成员;
- 初始化:对第一成员做初始化。
常用场合:得到一个整数(int)的内部字节(同理可得double/float)
#include <stdio.h>
typedef union {
int i;
char ch[sizeof(int)];
} CHI;
int main()
{
CHI chi;
chi.i = 1234;
int j;
for ( j=0; j<sizeof(int); j++) {
printf("%02hhX", chi.ch[j]);
}
printf("\n");
return 0;
}
拓展知识:x86架构,小端,在内存中存放数据时,低位在前。