(内容为学习笔记,如有错误,还望指正,如有遗漏,还望补充)
1.结构体
1)结构体定义
开发过程中,又是一个变量已经不满足我们对某一事物(对象)的表述了,这时候就需要使用多个变量来描述同一个事物,例如游戏中游戏角色有攻击力、防御力、生命值、法力值等,我们需要一种语法,能够将所有的属性封装成一个类型,即结构体。
Role //结构体名
{
int act; //结构体变量 攻击力
int def; //结构体变量 防御力
float HP; //生命值
float MP; //法力值
};
结构体的本质是类型,是自定义的用来封装属性的类型。
2)定义结构体变量
/*
定义结构体类型的关键字 struct
student 是我们定义的结构体类型的名字
{
结构体的属性
};//注意,这有分号。
结构体的{}不表示作用域
所以在{}内的代码,不是定义变量语句。
{}内的代码,只是说明结构体类型中包含的属性有哪些。
*/
struct student //这是结构体类型,在定义出结构体变量之前,不分配任何内存。
{
char name[20];
char number[20];
int grade;
float score;
};
int main()
{
/*
定义结构体变量 struct 结构体名 变量名;
注意:定义结构体变量时,struct不能省。
定义结构体变量之后,结构体变量中的成员才会被定义出来。
此时,变量a中包含了两个数组,两个变量。
此时a中的所有成员都没有有效值。
没有声明struct student a 就不给分配内存!
*/
struct student a;
printf("%d\n", sizeof(a));//48
return 0;
}
3)访问结构体成员变量
成员运算符
. //p.name 表示机构体变量p中的成员变量name
二元运算,左值结构体变量,右值成员名称,运算得到结构体的成员对象本身,成员运算符的运算结果不是数值。
//a.name 运算得到变量a中的name成员本身,由于name是数组,所以a.name得到的是数组名
strcpy(a.name, "Alice");
//a.number 运算得到变量a中的number成员本身,由于number是数组,所以a.number得到的是数组名
strcpy(a.number,"17001001001");
//a.grade运算得到a中的grade成员本身,是一个int类型的变量
a.grade = 90;
//a.score运算得到a中的score成员本身,是一个float类型的变量
a.score = 6000.00;
4)输出结构体成员变量
不能直接把结构体变量格式化,只能一个一个属性单独进行格式化。
printf("name:%s,number:%s,grade:%d,score:%f\n", a.name, a.number, a.grade, a.score);
5)结构体指针
结构体指针,就是普通的指针变量,和我们会之前学习的语法都是一样的。
成员运算符
->
成员运算符
.
两个成员运算符的算法是相同,但是两者的左值类型不同, .的左值是结构体变量,->的左值是结构体指针。
6)结构体数组
初始化:
//完全初始化:
struct Student students[2] = {
{"xiaoming", 18, 10010, "huaqing"},
{"xiaoqiang", 19, 10011, "huaqing"}
};
//部分初始化:
struct Student students[3] = {
{"xiaoming", 18, 10010, "huaqing"},
{"xiaoqiang", 19, 10011, "huaqing"}
};
//部分初始化,没有值的元素,所有属性默认都是0
//默认初始化:
struct Student students[] = {
{"xiaoming", 18, 10010, "huaqing"},
{"xiaoqiang", 19, 10011, "huaqing"}
};
7)结构体嵌套
struct date
{
int year;
int month;
int day;
};
struct id_card
{
char name[20];
struct date birthday;
};
8)结构体大小计算
结构体的大小计算中,我们应该先了解一个“行”的概念,结构体的大小一定是一“行”大小的整数倍,“行”的大小由结构体中占内存最大的成员决定。
例如下面的例子中,c是结构体student类型中最大的成员变量,则这个结构体变量的大小就是short的整数倍。
#include <stdio.h>
struct student
{
char a;
char b;
short c;
};
int main()
{
struct student s;
printf("%p %p %p %p\n",&s, &s.a, &s.b, &s.c);
/*
打印会发现,&s和&s.a的值相同,但是两个地址的类型是不同的!可以+1验证
&s.b是&s.a的值+1
&s.c是&s.b的值+1
*/
printf("%d\n", sizeof( struct student) );//4
}
char a | char b |
short c | short c |
再如下,结构体的成员变量在存储时依次存储,存储不下时会另起一行,每行大小是最大成员变量占用内存大小,a之后存不下b,所以b另起一行存储,c同理,所以占用了6个字节。
#include <stdio.h>
struct student
{
char a;
short b;
char c;
};
int main()
{
struct student s;
printf("%p %p %p %p\n", &s, &s.a, &s.b, &s.c);
printf("%d\n", sizeof( struct student) ); //6
}
char a | |
short b | short b |
char c |
又如下,系统在分配地址的时候,除了char类型,都习惯分配偶数地址。
#include <stdio.h>
struct student
{
int a;
char b;
short c;
char d;
};
int main()
{
struct student s;
printf("%p %p %p %p %p\n",&s, &s.a, &s.b, &s.c, &s.d);
printf("%d\n", sizeof( struct student) ); //12
}
int a | int a | int a | int a |
char b | short c | short c | |
char d |
最后,在没有特殊强调是64位系统时,都按照32位系统算。32位系统“行”最多4字节。64位系统“行”最多8字节。
在32位系统中,int一定是独占一“行”,double一定是独占二“行”。
struct Node
{
char c;
double d;
};
int main()
{
printf("%d\n", sizeof(struct Node));
return 0;
}
char c | |||
double d | double d | double d | double d |
double d | double d | double d | double d |