文章目录
- 一、结构体
- 1、结构体概述
- 2、结构体类型的定义方式
- (1)先定义结构体类型,再定义结构体变量
- (2)结构体类型、变量同时定义
- (3)一次性结构体
- 3、结构体成员的初始化
- (1)结构体初始化
- (2)清空结构体
- (3)键盘给结构体赋值
- 4、结构体成员操作
- 5、相同类型的结构体操作
- 6、结构体嵌套
- 7、结构体数组
- 8、结构体指针变量
- 9、结构体数组元素的指针
- 10、结构体的指针指向堆区空间
- 11、结构体深层拷贝
- 12、结构体与结构体成员都在堆区
- 13、结构体对齐
- (1)结构体自动类型对齐
- (2)结构体嵌套结构体 自动对齐规则
- (3)结构体强制对齐
- 14、位域
- 二、共用体
- 三、枚举enum
一、结构体
1、结构体概述
将多种数据结构封装在一起 形成新的结构叫结构体
每种数据结构 都有自己独立的空间
结构体的关键字 struct
2、结构体类型的定义方式
(1)先定义结构体类型,再定义结构体变量
struct str
{
int num;//结构体成员
char name;
};
struct str array;//定义结构体变量
(2)结构体类型、变量同时定义
struct str
{
int num;//结构体成员
char name;
}array;//定义结构体变量
struct str data;//定义结构体新变量
(3)一次性结构体
struct
{
int num;
}asd;//定义变量
3、结构体成员的初始化
(1)结构体初始化
#include <stdio.h>
struct stu
{
int num;
char str[128];
int data[32];
};
int main(int argc, char const *argv[])
{
struct stu array = {100,"hello",{200,300}};
printf("%d %s %d\n",array.num, array.str, array.data[1]);
return 0;
}
(2)清空结构体
#include <stdio.h>
#include <string.h>
struct stu
{
int num;
char str[128];
int data[32];
};
int main(int argc, char const *argv[])
{
struct stu array;
memset(&array,0,sizeof(array));
printf("%d\n",sizeof(array));//260 = 1*4+128+32*4
return 0;
}
(3)键盘给结构体赋值
#include <stdio.h>
#include <string.h>
struct stu
{
int num;
char str[128];
int data[32];
};
int main(int argc, char const *argv[])
{
struct stu array;
memset(&array,0,sizeof(array));
scanf("%d %s",&array.num, array.str);//键盘获取内容
printf("%d %s\n",array.num, array.str);
return 0;
}
#include <stdio.h>
#include <string.h>
struct date
{
int num;
char str[128];
};
int main(int argc, char const *argv[])
{
struct date arr[3];
memset(arr,0,sizeof(arr));
int n = sizeof(arr)/sizeof(arr[0]);
//获取键盘数组
printf("请输入%d个学生信息num str\n",n);
int i = 0;
for ( i = 0; i < n; i++)
{
scanf("%d %s",&arr[i].num,arr[i].str);
}
for ( i = 0; i < n; i++)
{
printf("%d %s\n",arr[i].num,arr[i].str);
}
}
4、结构体成员操作
int类型
zxc.num +=100;
char类型
strcpy(zxc.str,"name");
5、相同类型的结构体操作
#include <stdio.h>
#include <string.h>
struct stu
{
int num;
char str[128];
int data[32];
};
int main(int argc, char const *argv[])
{
struct stu array = {100,"hello",200};
struct stu array2;
#if 1
//方式一;成员逐个赋值
array2.num = array.num;
*array2.data = *array.data;
strcpy(array2.str,array.str);
#elif 0
//方式二;相同类型的结构体变量,可以直接赋值
array2 = array;
#else
//方式三
memcpy(&array2,&array,sizeof(array));
#endif
printf("%d %s %d\n",array2.num,array2.str, *array2.data);
return 0;
}
6、结构体嵌套
#include <stdio.h>
#include <string.h>
struct stu
{
int num;
char str[128];
int data[32];
};
struct date
{
int year;
int month;
int day;
struct stu ob;
};
int main(int argc, char const *argv[])
{
struct date lucy = {2023,07,28,{666,"xixi",999}};
printf("year=%d month=%d day=%d\n",lucy.year,lucy.month,lucy.day);
printf("str = %s data = %d\n",lucy.ob.str,*lucy.ob.data);
return 0;
}
结果:
year=2023 month=7 day=28
str = xixi data = 999
7、结构体数组
#include <stdio.h>
#include <string.h>
struct stu
{
int num;
char name[128];
};
int main(int argc, char const *argv[])
{
struct date2 arr[3] = {{100,"qwe"},{232,"asdas"},{7897,"ksjs"}};
int n = 0;
n = sizeof(arr)/sizeof(arr[0]);
int i = 0;
for ( i = 0; i < n; i++)
{
printf("%d %s\n",arr[i].num,arr[i].name);
}
return 0;
}
8、结构体指针变量
结构体指针变量 本质是指针变量 保存的是结构体变量的地址
p->num 根据地址获取num
(*p).num
左边是 地址 使用 ->
左边是 变量 使用 .
#include <stdio.h>
#include <string.h>
struct stu
{
int num;
char str[128];
int data[32];
};
int main(int argc, char const *argv[])
{
struct stu ob = {100,"xixi",200};
struct stu *p = &ob;
printf("%d %s %d\n",p->num,p->str,*(*p).data);
return 0;
}
9、结构体数组元素的指针
#include <stdio.h>
#include <string.h>
struct data
{
int num;
char str[128];
};
void input_stu_data(struct data *arr,int n)
{
printf("请输入%d个学生信息num arr\n",n);
int i = 0;
for ( i = 0; i < n; i++)
{
printf("请输入第%d个学生信息:",i+1);
scanf("%d %s",&(arr+i)->num,arr[i].str);
}
return;
}
void sort_arr_array(struct data *arr ,int n)
{
int i = 0;
for ( i = 0; i < n-1; i++)
{
int min = i;
int j = min +1;
for ( ; j < n; j++)
{
if(arr[min].num>arr[j].num)
min = j;
}
if(i != min)
{
struct data tmp = arr[min];
arr[min] = arr[i];
arr[i] = tmp;
}
}
return;
}
int main(int argc, char const *argv[])
{
struct data arr[5];
memset(arr,0,sizeof(arr));
int n = sizeof(arr)/sizeof(arr[0]);
//键盘输入
input_stu_data(arr,n);
//对结构体数组排序
sort_arr_array(arr , n);
int i = 0;
for ( i = 0; i < n; i++)
{
printf("%d %s\n",arr[i].num,arr[i].str);
}
return 0;
}
10、结构体的指针指向堆区空间
当结构体有指针成员时须为其申请指针空间
#include <stdio.h>
#include <string.h>
struct stu
{
int num;
char *name;
};
int main(int argc, char const *argv[])
{
struct stu lucy;
lucy.num = 100;
lucy.name = (char *)calloc(1,128);//申请空间
strcpy(lucy.name, "hellow world");
printf("%d %s\n",lucy.num,lucy.name);
printf("%c\n",lucy.name[1]);
lucy.name[1] = 'D';
printf("%d %s\n",lucy.num,lucy.name);
//释放lucy.name指向的堆区空间
if(lucy.name != NULL)
{
free(lucy.name);
lucy.name = NULL;
}
return 0;
}
11、结构体深层拷贝
如果结构体中含有指针成员,尽量使用深拷贝
(如果使用浅拷贝,拷贝完成后需要对lucy、ob申请的空间进行释放,由于指向同一空间,就造成空间重复释放,所以使用深拷贝,为ob重新申请一个空间,使用完成后进行释放)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu
{
int num;
char *name;
};
int main(int argc, char const *argv[])
{
struct stu lucy;
struct stu ob;
lucy.num = 100;
lucy.name = (char *)calloc(1,128);//申请空间
ob.name = (char *)calloc(1,128);
ob.num = lucy.num;
strcpy(ob.name,lucy.name);
strcpy(lucy.name, "hellow world");
printf("%d %s\n",lucy.num,lucy.name);
printf("%c\n",lucy.name[1]);
lucy.name[1] = 'D';
printf("%d %s\n",lucy.num,lucy.name);
//释放lucy.name指向的堆区空间
if(lucy.name != NULL)
{
free(lucy.name);
lucy.name = NULL;
}
if(ob.name != NULL)
{
free(ob.name);
ob.name = NULL;
}
return 0;
}
如果结构体中没有指针成员 赋值 不会出现浅拷贝。
如果结构体中有指针成员 赋值 容易造成浅拷贝
12、结构体与结构体成员都在堆区
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu
{
int num;
char *name;
};
int main(int argc, char const *argv[])
{
//结构体本身在堆区
struct stu *p = NULL;
p = (struct stu *)calloc(1,sizeof(struct stu));
//为结构体指针成员申请空间
p->name = (char *)calloc(1,128);//(*p).name = (char *)calloc(1,128);
p->num = 100;
strcpy(p->name,"hello world");
printf("%d %s\n",p->num,p->name);
//先释放成员空间
if(p->name != NULL)
{
free(p->name);
p->name = NULL;
}
//在释放结构体空间
if(p != NULL)
{
free(p);
p = NULL;
}
}
13、结构体对齐
(1)结构体自动类型对齐
①确定分配单位(一行分配多少字节)
结构体中最大的基本类型长度决定
②确定成员偏移量
成员偏移量 = 成员本身类型的整数倍
③收尾工作
结构体的总大小 = 分配单位整数倍
#include <stdio.h>
struct array
{
char str;
int num;
char name;
};
int main(int argc, char const *argv[])
{
struct array A;
printf("%d\n",sizeof(A));
printf("%p\n",&A.str);
printf("%p\n",&A.num);
printf("%p\n",&A.name);
return 0;
}
结果:
12
000000000061FDE4
000000000061FDE8
000000000061FDEC
案例1:画出以下结构体的对齐
struct Data
{
char a;
short b;
int c;
char d;
short e;
};
(2)结构体嵌套结构体 自动对齐规则
①确定分配单位(一行分配多少字节)
所有结构体中最大的基本类型长度决定
②确定成员的偏移量
普通成员偏移量 = 成员自身类型的整数倍
结构体成员的偏移量 = 结构体中最大的基本类型整数倍
③收尾工作
结构体成员大小 = 该结构体中最大的基本类型整数倍
结构体的总大小 = 分配单位整倍数
#include <stdio.h>
struct data1
{
char str;
char str2;
int num;
};
struct data2
{
char str1;
struct data1 bob;
short num1;
};
int main(int argc, char const *argv[])
{
struct data2 bob2;
printf("%d\n",sizeof(bob2));
//结构体自动对齐
printf("%p\n",&bob2.str1);
printf("%p\n",&bob2.bob.str);
printf("%p\n",&bob2.bob.str2);
printf("%p\n",&bob2.bob.num);
printf("%p\n",&bob2.num1);
return 0;
}
结果:
16
000000000061FDE0
000000000061FDE4
000000000061FDE5
000000000061FDE8
000000000061FDEC
(3)结构体强制对齐
#prangma pack(value)是指定对齐值
valu值为1,2,4,8,16
①确定分配单位(一行分配多少字节)
分配单位 = min(结构体中最大的基本类型,value)
②确定成员的偏移量
成员偏移量 = 成员自身类型的整数倍
③收尾工作
结构体的总大小 = 分配单位整倍数
#include <stdio.h>
#pragma pack(2)
struct array
{
char str;
int num;
char name;
};
int main(int argc, char const *argv[])
{
struct array A;
printf("%d\n",sizeof(A));
printf("%p\n",&A.str);
printf("%p\n",&A.num);
printf("%p\n",&A.name);
return 0;
}
结果:
8
000000000061FDE8
000000000061FDEA
000000000061FDEE
14、位域
在结构体中,以位为单位的成员,称之为位段(位域)
struct A
{
unsigned int a:2;
unsigned int b:6;
unsigned int c:4;
unsigned int d:3;
unsigned int e;
}data;
a为无符号整型,大小只占2位二进制位
位域可以是unsigned int ,unsigned char
没有非位域隔开的位域 叫相邻位域(a,c)
相邻位域可以压缩
位段的大小不能超过存储单元的大小
不要对位域取地址。
如:a=9 == 1001 ,但a的存储单元只有两位所以只能存储01
b=9 == 1001,b的存储单元有6位可以存储1001
#include <stdio.h>
struct A
{
unsigned int a:2;
unsigned int b:6;
unsigned int c:4;
unsigned char :8;
unsigned int d:3;
unsigned int e;
}data;
int main(int argc, char const *argv[])
{
printf("sizeof(struct A)=%lu\n",sizeof(struct A));
return 0;
}
无意义位段
#include <stdio.h>
struct A
{
unsigned char a : 2;
unsigned char :2; //两位无意义位段
unsigned char b : 2;
unsigned char c : 2;
//int num;
};
int main(int argc, char const *argv[])
{
printf("sizeof(struct A)=%lu\n",sizeof(struct A));
}
#include <stdio.h>
struct B
{
unsigned char addr : 2;
unsigned char : 1;
unsigned char opt :2;
unsigned char : 1;
unsigned char data : 2;
};
int main(int argc, char const *argv[])
{
struct B reg;
reg.addr = 2;
reg.opt = 1;
reg.data = 1;
}
二、共用体
共用体:所有成员共享同一块空间
结构体:所有成员拥有独立空间
union C
{
int a;
short b;
char c;
};
成员a b c共享同一块空间。空间大小 由最大的成员空间决定,即c
union C ob;
ob.a = 10;//空间内容为10
ob.b = 20;//空间内容为20
ob.c = 30;//空间内容为30
ob.a + ob.b + ob.c = 90;
三、枚举enum
枚举:将枚举变量要赋的值一一列举出来
#include <stdio.h>
#include <string.h>
enum ha{data1,data2,data3=14,data4};
int main(int argc, char const *argv[])
{
enum ha num = data2;
printf("%d\n",num);
}
枚举默认从0开始依次递增即,data1 = 0 ; data2 = 1 ; data3 = 14 ; data4 = 15 ;
四、如有错误欢迎指正
如要转发请告知