1.结构体的定义
基本数据类型 (内置类型) 原来就有 如:int double char 等等
而结构体类型 —> 自定义类型
设计一个结构体类型
struct 类型名字
{
成员列表(属性)
};
设计一个学生类型:
struct Student
{
char name[10];//名字 成员列表:可以为各种类型,如int 、double 等
int age;//年龄
int score;//分数
} ;// 注意要以分号结尾
定义结构体变量:
类型(struct Student) + 变量名称 (stu)
struct Student stu ;
结构体的嵌套
将定义的结构体看作一个数据类型,放到另一个结构体内部作为成员。
struct Address address
{
int home_ID;
};
struct Student
{
const char* name;
int age;
int weight;
struct Address address; //结构体类型的成员
};
2.所占内存大小
类型设计时,不占内存 。
//此时不占用内存
struct Student
{
} ;
// 注意要以分号结尾
但当使用数据类型来定义变量时就占用内存
结构体大小:
内存对齐规则:
-
结构体变量的首地址(VS下从偶数地址开始),必须为结构体变量中最大数据的成员所占字节数的整数倍
-
结构体变量中每个成员的地址相对于首地址的偏移量,必须为该成员数据类型所占大小的整数倍
-
结构体变量的总大小必须为该结构体变量中最大基本数据类型所占字节的整数倍(如果其中有嵌套的结构体类型,也要将该结构体类型中的基本数据类型进行比较)
如:结构体
struct A
{
char a;
int b;
} ;// 注意要以分号结尾
结构体所占字节为5,但根据规则 cpu会进行内存对齐,经过对齐之后结构体大小就为8字节
例子:
struct Student {
char name[10];//名字 成员列表:可以为各种类型,如int double 结构体
int age;//年龄
int score;//分数
} ;// 注意要以分号结尾
根据内存对齐规则得结构体占内存大小:
char name[10] //占10个字节
int age
//占4个字节 因name最后一个存放在地址为09,不为4的倍数,则进行内存对齐,在09后加上2个字节,age的首地址存放在地址为12的位置
int score //占4个字节,score首地址存放在16
共20个字节
对于name 还可以这样设计
struct Student {
const char* name;//存放张三所在的地址(位于数据区)
int age;//年龄
int score;//分数
};
在内存上所占大小:
const char* name 占4字节
name放的为一个地址,为存放张三所在的地址(位于数据区)
共占12个字节
在不同平台中,对齐的按照的大小也不同,在VS中默认为8字节
但是可以认为规定对齐的大小
可以按照下面方法来规定:
#pragma pack(n) // n 为规定对齐的大小 对齐方式开始 预处理指令
结构体
#pragma pack() //对齐方式结束
#pragma pack(2) //对齐方式开始 预处理指令
struct Student
{
char a;
int age;//年龄
};#pragma pack() //对齐方式结束
-
首先char占1个字节
-
来到int age 占4个字节,但因为首地址为01,本来要加3个字节,但是因为人为规定对齐大小为2,将2与
4进行比较选择小的对齐,所以按照2对齐,char后只加一个字节 -
再根据规则,结构体总大小为最大基本类型的整数倍,再加2字节,故结构体大小为8字节
-
在使用和设计时,应优先选择所占字节更小的结构体。
3.用typedef来重命名
可以用typedef来重命名,这样在之后使用时可以直接用重命名。
可以用 Student 代替 struct Student 来定义结构体变量,更加方便。
//方式一
typedef struct Student Student;
//方式二
typedef struct Student
{
const char* name;
int age;//年龄
int score;//分数
}Student;//重用名
使用:
Student str ;//代替struct Student str;
指针类型结构体进行重命名
//方式一
typedef struct Student* PStu;
//方式二
typedef struct Student
{
const char* name;
int age;//年龄
int score;//分数
}Student,*PStu;//重用名
使用:
PStu pstr = &str;//struct Student* pstr = &str;
4.进行成员的访问
-
通过 . (成员访问符) 访问
stu.name;
stu.age;
stu.score; -
结构体与指针结合
Student* ptr = &s;//结构体变量指针 使之指向结构体变量s
printf(“%s\n”,(*ptr).name);//1 通过解引用+ . 访问
printf(“%s\n”,ptr->name);//2 通过指针的指向符来访问
5.结构体的使用
定义结构体
struct Student {
const char* name;
int age;//年龄
int score;//分数
};
1.普通结构体
int main()//定义一个结构体变量 赋值 ,通过.访问 ,打印结构体的值
{
struct Student stu = {"张三",10,100};//对结构体变量stu进行初始化(赋值)
//可以通过结构体变量来进行成员的访问
printf("%s\n",stu.name);
return 0;
}
运行结果:
2.数组类型结构体
int main()
{
//定义一个结构体数组,赋值 ,通过.访问 ,打印结构体的值
struct Student arr[] = {{"zs",10,100},{"ls",9,99},{"ww",11,90}};
int len = sizeof(arr)/sizeof(arr[0]);
for(int i = 0;i<len;i++)
{
printf("第%d个学生 名字:%s 年龄:%d 分数:%d\n",i,arr[i].name,arr[i].age,arr[i].score);
}
return 0;
}
其中arr+1就加一个结构体的大小
运行结果:
6.练习题:对学生数组进行排序
- 要求:
按照学生成绩对学生数组进行冒泡排序(升序)
若成绩相同,按姓名(降序排序)
- 定义结构体,并重命名为Student
typedef struct Student {
const char* name;
int age;//年龄
int score;//分数
}Student;
- 通过冒泡排序来对成绩比大小,按照升序排序。排序完后再对其成绩相同的学生按照名字进行降序排序。
void BubbleSort(Student *s,int len)
{
Student ss;
for (int i = 0; i < len; i++)//对成绩进行升序排序
{
for (int j = 0; j < len - i -1; j++)
{
if (s[j].score > s[j+1].score)
{
ss = s[j];
s[j] = s[j + 1];
s[j + 1] = ss;
}
}
}
for (int j = 0; j < len-1 ; j++)//对成绩相同者进行降序排序
{
if (s[j].score == s[j + 1].score)
{
if (strcmp(s[j].name, s[j + 1].name) >= 0) { break; }
else
{
ss = s[j + 1];
s[j + 1] = s[j];
s[j] = ss;
}
}
}
}
- 测试看是否正确
int main()
{
struct Student s[] = {{"zs",10,100},{"awls",9,99},{"wa",11,99}};
int len = sizeof(s) / sizeof(s[0]);
BubbleSort(s, len);
for (int i = 0; i < len; i++)
{
printf("第%d个学生 名字:%s 年龄:%d 分数:%d\n", i,s[i].name, s[i].age, s[i].score);
}
return 0;
}
运行结果: