一、结构体类型的概念及定义
构造类型:
不是基本类型的数据结构也不是指针,它是若干个相同或不同类型的数据构成的集合
常用的构造类型有数组、结构体、共用体
- 数组用于保存多个相同类型的数据
- 结构体常用于保存多个不同类型的数据
#include <stdio.h>
// 注意:一般结构体类型都会定义在全局,也就是main函数的外面
// 所以在定义结构体类型的同时定义变量,这些变量一般都是全局变量
// 定义完类型之后定义的结构体变量,内存分配要看定义的位置在哪儿
struct stu{
int num;
char name[20];
char sex;
}lucy, bob, lilei;
struct stu xiaoming,xiaohong;
// 无名结构体由于没有结构体名,所以定义完之后是无法在定义结构体变量的,只能在定义类型的同时定义结构体变量
struct {
int num;
char name[20];
char sex;
}lucy1, bob2, lilei3;
// 给结构体类型取别名
// 通常将一个结构体类型重新起个类型名,用新的类型名替代原先的类型
typedef struct stu1{
int num;
char name[20];
char sex;
}STU1;
STU1 xiaoming11,xiaohong22;
int main()
{
return 0;
}
二、结构体变量的定义初始化及使用
#include <stdio.h>
struct stu{
int id;
char name[32];
char sex;
int age;
};
typedef struct {
int a;
int b;
char c;
}MSG;
int main()
{
struct stu wangwu;
struct stu wangwu1 = {1001, "wangwang", 'B', 20};
MSG msg1, msg = {100, 200, 'w'};
return 0;
}
结构体变量的使用
#include <stdio.h>
#include <string.h>
struct stu{
int id;
char name[32];
char sex;
int age;
} zhangsan;
int main()
{
// 结构体变量的使用
struct stu zhaoliu = {1001,"zhaoliu99",'B',20};
zhangsan.id = 1001;
// zhangsan.name = "zhangsan111"; // 错误用法 字符串常量的地址; 数组名是常量,不能赋值
strcpy(zhangsan.name, "zhangsan111");
zhangsan.sex = 'B';
zhangsan.age = 18;
printf("%d - %s - %c - %d\n", zhangsan.id, zhangsan.name, \
zhangsan.sex, zhangsan.age);
// 1001 - zhangsan111 - B - 18
printf("%d - %s - %c - %d\n", zhaoliu.id, zhaoliu.name, \
zhaoliu.sex, zhaoliu.age);
return 0;
}
在结构体中嵌套结构体
#include <stdio.h>
#include <string.h>
typedef struct{
int year;
int month;
int day;
}BD;
typedef struct{
int id;
char name[32];
BD birthday;
}STU;
void test2()
{
STU xiaoming;
xiaoming.id = 1001;
strcpy(xiaoming.name, "xiaoming66");
xiaoming.birthday.year = 2002;
xiaoming.birthday.month = 12;
xiaoming.birthday.day = 20;
printf("%d - %s - %d:%d:%d\n", xiaoming.id, xiaoming.name,\
xiaoming.birthday.year, xiaoming.birthday.month, xiaoming.birthday.day);
// 1001 - xiaoming66 - 2002:12:20
}
int main()
{
test2();
return 0;
}
结构体数组
结构体数组是个数组 ,由若干个相同类型的结构体变量构成的集合
#include <stdio.h>
typedef struct{
int num;
char name[20];
float score;
}STU;
int main()
{
// 定义一个结构体数组
STU edu[3] = {
{101,"Lucy",78},
{102,"Bob",59.5},
{103,"Tom",85}
};
int i;
float sum = 0;
for(i = 0; i<3; i++)
{
sum += edu[i].score;
}
printf("avg: %f\n", sum / 3); // avg: 74.166667
return 0;
}
结构体指针
结构体的地址,结构体变量存放内存中,也有起始地址
我们定义一个变量来存放这个地址,那这个变量就是结构体指针变量
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stu{
int id;
char name[32];
char sex;
int age;
};
int main()
{
// 定义一个结构体指针变量
struct stu *s;
// 在堆区开辟结构体空间并将其地址保存在结构体指针变量中
s = (struct stu *) malloc(sizeof(struct stu));
s->id = 1001;
strcpy(s->name, "zhangsan555");
s->sex = 'B';
s->age = 20;
printf("%d - %s - %c - %d\n", s->id, s->name, s->sex, s->age);
// 1001 - zhangsan555 - B - 20
return 0;
}
结构体内存分配问题
为什么要有字节对齐?
用空间来换时间,提高cpu读取数据的效率
#include <stdio.h>
struct stu{
char a;
short b;
int c;
}temp;
struct stu1{
char a;
short b;
short b1;
int c;
}temp1;
int main()
{
printf("%d\n", sizeof(temp)); // 8个字节
printf("%p\n", &(temp.a)); // 00406430
printf("%p\n", &(temp.b)); // 00406432
printf("%p\n", &(temp.c)); // 00406434
printf("%d\n", sizeof(temp1)); // 12个字节
printf("%p\n", &(temp1.a)); // 00406424
printf("%p\n", &(temp1.b)); // 00406426
printf("%p\n", &(temp1.b1)); // 00406428
printf("%p\n", &(temp1.c)); // 0040642C
return 0;
}
#include <stdio.h>
// 注意看: 两个结构体short和int的位置不同
struct stu{
char a;
short b;
int c;
}temp;
struct stu1{
char a;
int c;
short b;
}temp1;
int main()
{
printf("%d\n", sizeof(temp)); // 8
printf("%p\n", &(temp.a)); // 00406430
printf("%p\n", &(temp.b)); // 00406432
printf("%p\n", &(temp.c)); // 00406434
printf("%d\n", sizeof(temp1)); // 12
printf("%p\n", &(temp1.a)); // 00406424
printf("%p\n", &(temp1.c)); // 00406428
printf("%p\n", &(temp1.b)); // 0040642C
return 0;
}
结构体内存分配 特例: double
#include <stdio.h>
// 结构体内存分配 特例: double
// 在gcc中占 12 字节 , a和b的地址差4个字节
// 在vc 中占 16 字节 , a和b的地址差8个字节
struct stu{
char a;
double b;
}temp;
int main()
{
printf("%d\n", sizeof(temp));
printf("%p\n", &(temp.a));
printf("%p\n", &(temp.b));
return 0;
}
- 位段
- 共用体
- 枚举