一、结构体类型定义
(1)在定义结构体类型的同时直接定义结构体类型变量
struct 结构体名(结构体类型标识符)//结构体类型标识符 就是 结构体名
{
数据类型 成员1;
数据类型 成员2;
……
数据类型 成员n;
}变量列表名;
花括号里面的是成员列表
在右花括号右边的是变量列表
如
struct student
{
long id;
float score[5];
int age;
char name[20];
}s1,s2,s3;
其中s1,s2,s3是全局变量
(2)先定义结构体类型,再定义结构体类型的变量,数组,指针变量
struct 结构体名(也叫做 结构体类型标识符)
{
数据类型 成员1;
数据类型 成员2;
……
数据类型 成员n;
};
struct 结构体名(也叫做 结构体类型标识符) 变量列表;
如;
struct student
{
long id;
float score[5];
int age;
char name[20];
};
struct stundent s1, per[5],*sp;
这里,s1 per[5] *sp 也是全局变量
二、结构体变量的初始化(顺序要一一对应)
(1)在定义结构体类型的同时直接定义结构体类型变量并且初始化
一般形式:
结构体变量名={初值};(注意:这是写在右花括号的后面)
struct number
{
int x;
float y;
}s1 = { 4,5.4 };
(2)先定义结构体类型,再定义结构体类型的变量,再来初始化
一般形式:
struct 结构体类型标识符 结构体变量名={初值};
struct number
{
int x;
float y;
}s1;
struct number s1 = { 4,5.4 };
(3)结构体类型数组的初始化
一般形式:
struct 结构体类型标识符 结构体变量数组名[ ]={ 初始化数据};
struct student
{
long id;
char name[20];
char sex;
int age;
}pers[3]; //当然这里pers[3]也可不写
struct student pers[3] = { {2001,"li li",'M',19},
{2003,"zhou zhou",'F',18},
{2002,"mao mao",'F',20} };
(4)结构体类型指针变量的初始化
一般形式:
struct 结构体类型标识符 * 结构体指针变量名=&结构体变量名;
struct student std; //std 是结构体变量
struct studnet* p = &std; //p是结构体指针变量。
存储单元的大小是结构体变量中所有成员所占用字节数的总和,可用sizeof求出,例如sizeofs(std)
三、一个结构体也可以做其它结构体类型的成员
(1)定义
struct number
{
int x;
float y;
}sp;
struct student
{
long id;
int age;
char sex;
char name[20];
struct number;
}ss;
struct number 作为了 struct student 的成员
(2)初始化
int main()
{
struct student ss = { 2023216337,18,'M',"zhangsan",{3,6.5} };
}
注意:1.字符要用单引号 ,字符串要用 双引号
2.初始化在一个结构体中作为成员的那个结构体,应该用花括号 把那个结构体的成员的初始化的值给包含起来 如 上代码所示 {3,6.5}
(3)打印成员的值
对结构体的引用可采用三种形式
1.结果体变量名.成员名
2.(*结构体指针变量). 成员名
3.结构体指针变量 ->(减号和大于号构成。它的优先级是所有运算符中最高的,左结合性)
i、这里采用第一种访问方法
对比以下两段代码
struct number
{
int x;
float y;
}sp;
struct student
{
long id;
int age;
char sex;
char name[20];
struct number; //注意这里没有 结构体number的变量sp
}ss;
int main()
{
struct student ss = { 2023216337,18,'M',"zhangsan",{3,6.5} };
printf("%d\t%d\t%c\t%s\t", ss.id, ss.age, ss.sex, ss.name);
printf("%d\t%f\t", ss.x, ss.y); //访问时,直接是ss.x 和ss.y
return 0;
}
struct number
{
int x;
float y;
}sp;
struct student
{
long id;
int age;
char sex;
char name[20];
struct number sp; //注意这里有结构体number的变量sp
}ss;
int main()
{
struct student ss = { 2023216337,18,'M',"zhangsan",{3,6.5} };
printf("%d\t%d\t%c\t%s\t", ss.id, ss.age, ss.sex, ss.name);
printf("%d\t%f\t", ss.sp.x, ss.sp.y); //访问时,要先通过sp连接桥梁,
// 才能顺利访问到x和y
return 0;
}
二者结果一样
ii、这里采用第一种访问方法
对比以下两段代码
struct number
{
int x;
float y;
}sp;
struct student
{
long id;
int age;
char sex;
char name[20];
struct number; //注意这里没有 结构体number的变量sp
}ss;
int main()
{
struct student ss = { 2023216337,18,'M',"zhangsan",{3,6.5} };
struct student* p = &ss;
printf("%d\t%f\t", ss.x, ss.y);
printf("\n");
printf("%d\t%f\t", (*p).x, (*p).y);
printf("\n");
printf("%d\t%f\t", p->x, p->y);
return 0;
}
struct number
{
int x;
float y;
}sp;
struct student
{
long id;
int age;
char sex;
char name[20];
struct number sp; //注意这里有结构体number的变量sp
}ss;
int main()
{
struct student ss = { 2023216337,18,'M',"zhangsan",{3,6.5} };
struct student* p = &ss;
printf("%d\t%d\t%c\t%s\t", ss.id, ss.age, ss.sex, ss.name);
printf("\n");
printf("%d\t%f\t", ss.sp.x, ss.sp.y); //访问时,要先通过sp连接桥梁,才能顺利访问到x 和y
printf("\n");
printf("%d\t%f\t", (*p).sp.x, (*p).sp.y);
printf("\n");
printf("%d\t%f\t", p->sp.x, p->sp.y); //->的优先级最高
return 0;
}
结果也一样
iii、总结:
1、当一个结构体作为另一个结构体的成员时,如果在struct 结构体名 后面加上了 这个作为成员的结构体的变量,那么,在打印 包含这结构体的 那另一个结构体的元素时,访问要用
这个形式:
大的结构体的变量名.作为成员的结构体的变量名.作为成员的结构体的成员名
如:ss.sp.x
2、当一个结构体作为另一个结构体的成员时,如果在struct 结构体名 后面没加上 这个作为成员的结构体的变量,那么,在打印 包含这结构体的 那另一个结构体的元素时,访问要用
这个形式:
大的结构体的变量名.作为成员的结构体的成员名
如:ss.x
3、第一种形式需要作为成员的结构体的变量名进行过渡
四、调用自定义函数来打印结构体成员
(1)函数形参为结构体
注意:形参里的结构体名要和实参的结构体名一致
而形参的变量名可以随意
如:void printf1(struct s kk) 其中s是保持一致的,kk是随意的
struct m
{
int x;
int y;
}mm;
struct s
{
float m;
char name[20];
char ch;
struct m mm; //这里有结构体m的变量mm,所以访问时要用mm过渡
}ss;
void printf1(struct s kk)
{
printf("%f\t%s\t%c\t%d\t%d\t", kk.m, kk.name, kk.ch, kk.mm.x, kk.mm.y);
//这里用了mm过渡
}
int main()
{
struct s ss = { 2.3,"jaychou",'C',{3,5} };
printf1(ss);
return 0;
}
结果:
(2)函数形参为结构体指针变量
注意:形参里的结构体名要和实参所代表的结构体名一致
再加上 *p,*号说明p是指针变量,p用来接收实参传送过来的地址
如:void printf2(struct s* p)
调用时实参写成 ---- &结构体变量)(当然是被打印的结构体的结构体变量)
struct m
{
int x;
int y;
}mm;
struct s
{
float m;
char name[20];
char ch;
struct m mm; //这里有结构体m的变量mm,所以访问时要用mm过渡
}ss;
void printf2(struct s* p)
{
printf("%f\t%s\t%c\t%d\t%d\t",p->m, p->name,(*p).ch, (*p).mm.x, (*p).mm.y);
//这里要使用指针访问的那两种形式
}
int main()
{
struct s ss = { 2.3,"jaychou",'C',{3,5} };
//printf1(ss);
printf2(&ss);
return 0;
}
结果一致:
(3) 总结
第一种是把结构体拷贝一份,将新的这份进行操作,
第二种是把原来结构体地址传过去,操作的是它本身,
因为函数传参时是要压栈的
如果传递一个结构体对象时,结构体过大,参数压栈的系统开销比较大,所以会导致性能下降
结论:结构体传参的时候要传结构体的地址
五、结构体变量成员值的修改
struct m
{
int x;
int y;
}mm;
struct s
{
float m;
char name[20];
char ch;
struct m mm; //这里有结构体m的变量mm,所以访问时要用mm过渡
}ss;
void printf2(struct s* p)
{
printf("%f\t%s\t%c\t%d\t%d\t",p->m, p->name,(*p).ch, (*p).mm.x, (*p).mm.y);
//这里要使用指针访问的那两种形式
}
int main()
{
struct s ss = { 2.3,"jaychou",'C',{3,5} };
ss.ch = 'Y';
ss.m = 9.58;
ss.mm.x = 7;
ss.mm.y = 9;
strcpy(ss.name, "ZHOUZISONG");
printf2(&ss);
return 0;
}
注意:
1.字符,整形,浮点型数据直接重新赋值
2.字符串要用strcpy函数(记得包含 #include <string.h>)进行拷贝(因为name是个数组名,只是个地址)
前后结果对比: