文章目录
- 结构体
- 结构体声明
- 定义结构体变量
- 访问结构体成员
- 结构体的初始化
- 结构体列表初始化
- 结构体指定初始化
- 结构体数组
- 结构体指针
- 结构体指针获取结构体成员
- 结构体指针作为函数参数
- 字节对齐
- 1、按一个字节对齐
- 2、按编译器默认进行对齐
- 3、字节对齐规则
- 字节对齐的原因
- 前言
- 对齐的作用和原因
- 总结
结构体
在C语言中,可以使用结构体来存放一组不同的数据类型,提高数据的表示能力
结构体是一种集合,可以包含多个变量或数组,类型可以先相同也可以不同,包含的变量或数组称为结构体的成员
结构体声明
结构声明:描述了一个结构的组织布局
struct test{
int arr[MAXTITL];
char ch[4];
};
该声明描述了一个由大小为MAXTITL的整型数组和一个char数组类型变量组成的结构体
告诉编译器如何表示数据,但并未让编译器为数据分配空间
可以把该声明当成模板,描绘出结构是如何存储数据的,但与C++中的模板是不同的概念
定义结构体变量
结构体是一种自定义数据类型,可以用来定义变量
struct test t1,t2;
定义的t1,t2,都是test类型,都具有同test一样的变量
定义的结构体变量是编译器根据test"模板"为变量分配空间
声明结构体的同时定义结构体变量:将定义的结构体变量名放到结构体定义后面
#include <stdio.h>
struct test{}t1;
struct tert{
int arr[10];
}t2;
int main()
{
printf("sizeof(t1)=%zd\n",sizeof(t1));
printf("sizeof(t2)=%zd\n",sizeof(t2));
return 0;
}
访问结构体成员
使用结构成员运算符——点(.)访问结构体中的成员
结构体变量名.结构体成员
结构体的初始化
结构体列表初始化
结构体使用初始化列表进行初始化,可对结构体成员进行逐一赋值和部分赋值
#include <stdio.h>
struct test{
int num ;
float value;
};
int main()
{
struct test t1 = {6,7.7}; //逐一初始化
struct test t2 = {5}; //部分初始化
printf("t1.num=%d\n",t1.num);
printf("t1.value=%f\n",t1.value);
printf("t2.num=%d\n",t2.num);
printf("t2.value=%f\n",t2.value);
return 0;
}
结构体指定初始化
结构器可以使用指定初始化器通过点运算符和结构体成员名对特定的结构体成员进行指定初始化
#include <stdio.h>
struct test{
int num ;
float value;
int count;
};
int main()
{
struct test t1 = {.value = 5.5,.count = 10};
printf("t1.num=%d\n",t1.num);
printf("t1.value=%f\n",t1.value);
printf("t1.count=%d\n",t1.count);
return 0;
}
结构体数组
结构体数据就是指数组中的每一个元素都是结构体
#include <stdio.h>
struct test{
int num ;
float value;
char ch;
};
int main()
{
struct test testArr[3]={ {1,1,2},{3,3,4},{5,5,6} };
for(int i = 0; i<3 ; i++)
{
printf("testArr[%d].num=%d\n",i,testArr[i].num);
printf("testArr[%d].value=%f\n",i,testArr[i].value);
printf("testArr[%d].ch=%d\n",i,testArr[i].ch);
}
return 0;
}
结构体指针
当一个指针变量指向结构体时,称为结构体指针
struct 结构体名 *变量名;
结构体变量名与数组名不一样,数组名在表达式中会被转换成数组指针,而结构体变量名不会,无论在任何表达式中标表示的都是整个结构体本身,要活的结构体变量的地址,则必须使用取地址符&
结构体指针获取结构体成员
通过结构体指针获取结构体成员的方式
1、(*ptr).structMember
2、ptr->structMember
.运算符高于*,所以(*ptr)括号不能少
#include <stdio.h>
struct test{
int num;
char ch;
double doub;
}t1;
int main()
{
struct test t1 = {5,'A',5.6};
struct test *ptr = &t1;
//解引用和点运算符
printf("type1:(*ptr).num=%d\n",(*ptr).num);
//指针
printf("type2: ptr->ch=%c\n",ptr->ch);
return 0;
}
结构体指针作为函数参数
结构体变量名代表整个结构体变量本身,当把结构体变量本身作为参数传递时,结构体内部的结构体成员较多时会造成时间和空间开销大,影响程序的运行效率
使用结构体指针作为参数传递时,因为传递的是地址,会比原本含有较多结构体的结构体变量更加块,但是也会造成结构体变量数据被修改的可能
#include <stdio.h>
#include <time.h>
struct test{
int num;
char ch;
double doub;
}t1;
void printA(struct test str)
{
str.num += 5;
printf("printA函数的num=%d\n",str.num);
}
void printB(struct test* te)
{
te->num += 15;
printf("printB函数的num=%d\n",te->num);
}
int main()
{
clock_t start, finish,start1,finish1;
struct test t1 = {5,'A',5.6};
struct test *ptr = &t1;
start = clock();
printA(t1);
finish = clock();
double Total_time = (double)(finish - start);
printf("printA函数之后,main函数的num=%d\n",t1.num);
printf("printA运行时间=%f\n",Total_time);
start1 = clock();
printB(ptr);
finish1 = clock();
double Total_time1 = (double)(finish1 - start1);
printf("printB函数之后,main函数的num=%d\n",t1.num);
printf("printB运行时间=%f\n",Total_time1);
return 0;
}
字节对齐
结构体中的各个成员理论上在内存中都是连续存储的,但实际上是根据字节对齐规则进行存储的
#pragma pack(n)
指定按照n字节对齐规则进行存储
1、按一个字节对齐
#include <stdio.h>
//调整结构体的边界对齐,按一个字节对齐
#pragma pack(1)
struct test{
int num;
char ch[4];
double doub;
char cha;
}t1;
int main()
{
printf("siezof(t1)=%zd\n",sizeof(t1));
return 0;
}
2、按编译器默认进行对齐
3、字节对齐规则
字节对齐的基本规则
- 结构体内部任何K字节的基本对象相对于结构体首地址的偏移,必须是K的整数倍
- 结构体变量的首地址能够被其最宽基本类型成员的大小所整除
- 结构体的总大小为结构体最宽基本类型成员大小的整数倍
#include<stdio.h>
struct bitField{
int num : 16;
int com :8;
char cn :4;
int count :16;
}b1;
struct test{
int num;
char a;
int b;
int c;
char e[5];
}t1;
int main()
{
printf("sizeof(b1)=%zd\n",sizeof(b1));
printf("sizeof(t1)=%zd\n",sizeof(t1));
return 0;
}
字节对齐的原因
前言
计算机内存是以字节(Byte)为单位划分的,理论上CPU可以访问任意编号的字节,但实际情况并非如此。CPU 通过地址总线来访问内存,一次能处理几个字节的数据,就命令地址总线读取几个字节的数据。32 位的 CPU 一次可以处理4个字节的数据,那么每次就从内存读取4个字节的数据
对齐的作用和原因
各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多
将一个数据尽量放在一个步长之内,避免跨步长存储,这称为内存对齐。在32位编译模式下,默认以4字节对齐;在64位编译模式下,默认以8字节对齐
总结
结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间,真正需要开辟内存空间来存储的是结构体成员变量,结构体中的各个成员理论上在内存中都是连续存储的,但实际上是根据字节对齐规则进行存储的
赶紧学习起来吧!我是一个正在努力找回自我的人,希望能和一起学习的人成长,有错误的地方请各位大佬帮忙指正,如果觉得有帮助就点个赞当作对我的一个小肯定❤,peace&love