1.为什么要定义结构体类型
储存一组逻辑相关属性相同或不同的数据
2.结构体变量的定义
struct 结构体名
{
数据类型 第一个成员名称
…
}; // " ; "不可省略
上为结构体模板,相当于声明了一种数据的组织形式
结构体名也是结构体标签,可以省略
typedef struct 结构体名 别名(一般大写)
{
数据类型 第一个成员名称
…
}变量名;
typedef 只是为一种已存在的类型定义一个新名字,并不是定义一种新的数据类型
别名也可以写在变量名的位置,一般大写,变量可以后续定义
3.结构体变量的引用
1.成员选择运算符(圆点运算符).
结构体变量名.成员名
当出现结构体嵌套时:
例: stu.birthday.year
2.指向运算符(箭头运算符)->
先声明一个指向结构体变量的指针
eg:
typedef struct STUDENT
{
long studentID;
DATE birthday; //结构体嵌套
}stu;
typedef struct date //此处date为结构体标识
{
int year;
char month[10];
int day;
}DATE; //别名
STUDENT *pt = &stu; //声明一个指针变量并且指向该结构体
pt->studentID= //第一种引用形式
(*pt).studentID= //第二种
pt->birthday.year= //嵌套的引用
4.关于结构体变量的指针
typedef struct STUDENT
{
int score[4];
}stu[10];
STUDENT *pt=stu;
等价于
STUDENT *pt=&stu[0];
pt->score[0]引用的是stu[0]的值 等价于 stu[0].score[0]
而pt+1 表示从stu[0]指向stu[1]的首地址
5.向函数传递结构体
三种方法
- 用结构体的单个成员作为函数参数,向函数传递结构体的单个成员。(很少使用,因为与普通类型变量作为实参传递没有区别)
- 用结构体变量作为函数参数,向函数传递结构体的完整结构
将整个结构体的内容赋值给被调函数,是传值调用,不会影响相应实参结构体成员的值 - 用结构体指针或结构体数组做函数参数,向函数传递结构体的首地址
因为是传地址调用,所以在函数内部对于结构体的修改会影响到相应实参结构体成员的值
这种方法相对于第二种而言,效率更高,因为只传递一个地址
(2) eg:
void F( struct date p).
{
int year;
}
struct date
{
...
}
main()
{
struct date d;
d.year=1000;
F(d);
....
}
(3) eg:
void F( struct date *pt).
{
int year;
}
struct date
{
...
}
main()
{
struct date d;
d.year=1000;
F(&d);
....
}
如若在形参声明时加上const
const stuct date *pt 则不能对对应的实参结构体的数值进行修改
6.使用结构体封装函数的好处
- 精简参数个数(防止过多使用全局变量)
可以把多个函数中用到的变量封装进结构体,调用时调用结构体即可 - 使函数接口更加简洁
- 可扩展性更好
7.补充注意
<1>结构体只能用来赋值,其他操作都不行
在结构体中数组可以直接赋值但字符数组不可以,应使用strcpy
eg: strcpy(stu.name,“王”);
<2>结构体数组
eg:
student[0]:代表第一个学生,结构体声明的一套成员,都有这个学生的一个
需要的时候直接调用即可,比如 student[0].name 等等
相对于的,student[1],就代表第二个学生