C语言结构体
一、结构体基础知识
1.结构体类型的定义
2.结构体变量的定义
3.结构体变量的初始化
4.结构体成员的使用
5.结构体赋值
赋值基本概念
深拷贝和浅拷贝
6.结构体数组
struct Person{
char name[64];
int age;
};
void test(){
//在栈上分配空间
struct Person p1[3] = {
{ "John", 30 },
{ "Obama", 33 },
{ "Edward", 25}
};
struct Person p2[3] = { "John", 30, "Obama", 33, "Edward", 25 };
for (int i = 0; i < 3;i ++){
printf("Name:%s Age:%d\n",p1[i].name,p1[i].age);
}
printf("-----------------\n");
for (int i = 0; i < 3; i++){
printf("Name:%s Age:%d\n", p2[i].name, p2[i].age);
}
printf("-----------------\n");
//在堆上分配结构体数组
struct Person* p3 = (struct Person*)malloc(sizeof(struct Person) * 3);
for (int i = 0; i < 3;i++){
sprintf(p3[i].name, "Name_%d", i + 1);
p3[i].age = 20 + i;
}
for (int i = 0; i < 3; i++){
printf("Name:%s Age:%d\n", p3[i].name, p3[i].age);
}
}
二、结构体嵌套指针
1.结构体嵌套一级指针
struct Person{
char* name;
int age;
};
void allocate_memory(struct Person** person){
if (person == NULL){
return;
}
struct Person* temp = (struct Person*)malloc(sizeof(struct Person));
if (temp == NULL){
return;
}
//给name指针分配内存
temp->name = (char*)malloc(sizeof(char)* 64);
strcpy(temp->name, "John");
temp->age = 100;
*person = temp;
}
void print_person(struct Person* person){
printf("Name:%s Age:%d\n",person->name,person->age);
}
void free_memory(struct Person** person){
if (person == NULL){
return;
}
struct Person* temp = *person;
if (temp->name != NULL){
free(temp->name);
temp->name = NULL;
}
free(temp);
}
void test(){
struct Person* p = NULL;
allocate_memory(&p);
print_person(p);
free_memory(&p);
}
2.结构体嵌套二级指针
//一个老师有N个学生
typedef struct _TEACHER{
char name[64];
char** students;
}Teacher;
void create_teacher(Teacher** teacher,int n,int m){
if (teacher == NULL){
return;
}
//创建老师数组
Teacher* teachers = (Teacher*)malloc(sizeof(Teacher)* n);
if (teachers == NULL){
return;
}
//给每一个老师分配学生
int num = 0;
for (int i = 0; i < n; i ++){
sprintf(teachers[i].name, "老师_%d", i + 1);
teachers[i].students = (char**)malloc(sizeof(char*) * m);
for (int j = 0; j < m;j++){
teachers[i].students[j] = malloc(64);
sprintf(teachers[i].students[j], "学生_%d", num + 1);
num++;
}
}
*teacher = teachers;
}
void print_teacher(Teacher* teacher,int n,int m){
for (int i = 0; i < n; i ++){
printf("%s:\n", teacher[i].name);
for (int j = 0; j < m;j++){
printf(" %s",teacher[i].students[j]);
}
printf("\n");
}
}
void free_memory(Teacher** teacher,int n,int m){
if (teacher == NULL){
return;
}
Teacher* temp = *teacher;
for (int i = 0; i < n; i ++){
for (int j = 0; j < m;j ++){
free(temp[i].students[j]);
temp[i].students[j] = NULL;
}
free(temp[i].students);
temp[i].students = NULL;
}
free(temp);
}
void test(){
Teacher* p = NULL;
create_teacher(&p,2,3);
print_teacher(p, 2, 3);
free_memory(&p,2,3);
}
三、结构体成员偏移量
//一旦结构体定义下来,则结构体中的成员内存布局就定下了
#include <stddef.h>
struct Teacher
{
char a;
int b;
};
void test01(){
struct Teacher t1;
struct Teacher*p = &t1;
int offsize1 = (int)&(p->b) - (int)p; //成员b 相对于结构体 Teacher的偏移量
int offsize2 = offsetof(struct Teacher, b);
printf("offsize1:%d \n", offsize1); //打印b属性对于首地址的偏移量
printf("offsize2:%d \n", offsize2);
}
四、结构体字节对齐
1.内存对齐
内存对齐原因
如何内存对齐
2.内存对齐案例
#pragma pack(4)
typedef struct _STUDENT{
int a;
char b;
double c;
float d;
}Student;
typedef struct _STUDENT2{
char a;
Student b;
double c;
}Student2;
void test01(){
//Student
//a从偏移量0位置开始存储
//b从4位置开始存储
//c从8位置开始存储
//d从12位置开存储
//所以Student内部对齐之后的大小为20 ,整体对齐,整体为最大类型的整数倍 也就是8的整数倍 为24
printf("sizeof Student:%d\n",sizeof(Student));
//Student2
//a从偏移量为0位置开始
//b从偏移量为Student内部最大成员整数倍开始,也就是8开始
//c从8的整数倍地方开始,也就是32开始
//所以结构体Sutdnet2内部对齐之后的大小为:40 , 由于结构体中最大成员为8,必须为8的整数倍 所以大小为40
printf("sizeof Student2:%d\n", sizeof(Student2));
}