恩施建设厅网站,wordpress美化导航菜单,wordpress个人网站主题,网站建设模拟实训题上篇文章介绍了一些常用的字符串函数#xff0c;大家可以去我的主页进行浏览。
各种源码大家可以去我的github主页进行查找#xff1a;Nerosts/just-a-try: 学习c语言的过程、真 (github.com)
今天要介绍的是#xff1a;结构体的相关内容 目录
一.结构体类型的声明
1.…上篇文章介绍了一些常用的字符串函数大家可以去我的主页进行浏览。
各种源码大家可以去我的github主页进行查找Nerosts/just-a-try: 学习c语言的过程、真 (github.com)
今天要介绍的是结构体的相关内容 目录
一.结构体类型的声明
1.结构的基础知识
2.结构的声明
3.特殊的声明
4.结构的自引用
5.结构体变量的定义和初始化 6.结构体传参 二.结构体内存对齐 1.对其规则
2.存在原因
3.减少浪费
编辑
4.修改默认对齐数
三.位段
1.什么是位段
2.位段的内存分配
3.位段的跨平台问题 一.结构体类型的声明
1.结构的基础知识 结构是一些值的集合这些值称为成员变量。结构的每个成员可以是不同类型的变量 2.结构的声明 结构的声明的原型 struct tag { member - list ; } variable - list ; eg
struct Student
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号
}; //分号不能丢
3.特殊的声明
匿名结构体
struct
{int a;char b;float c;
}x;struct
{int a;char b;float c;
}a[20], *p;
4.结构的自引用 我们也许回想在结构中包含一个类型为该结构本身的成员是否可以呢像下面这样
struct Node
{struct Node a1;int date[2];
};
这种情况下需要确保结构体类型的定义是在使用它的结构体类型之前。否则编译器将无法确定结构体类型的大小。
所以是不行的正确的自引用方式如下
struct Node
{int data;struct Node* next;
};
注意 typedef struct
{int data;Node* next;
}Node; 在定义指针变量next时使用了Node类型。由于Node类型的定义在当前代码中尚未完成编译器无法识别Node类型 正确的如下 typedef struct Node
{int data;struct Node* next;
}Node; 5.结构体变量的定义和初始化
struct Point
{int x;int y;
}p1; //声明结构体的同时定义变量p1struct Point p2; //定义结构体变量p2
//也可以
struct Point p3 {x, y};//初始化定义变量的同时赋初值。struct Stu //类型声明
{char name[15];//名字int age; //年龄
};
struct Stu s {zhangsan, 20};//初始化
struct Node
{int data;struct Point p;struct Node* next;
}n1 {10, {4,5}, NULL}; //声明结构体的同时嵌套初始化
struct Node n2 {20, {5, 6}, NULL};//单独结构体嵌套初始化 6.结构体传参
struct S
{int data[1000];int num;
};
struct S s { {1,2,3,4}, 1000 };
//结构体传参
void print1(struct S s)
{printf(%d\n, s.num);printf(%d\n, s.data[0]);printf(%d\n, s.data[1]);printf(%d\n, s.data[2]);
}
//结构体地址传参
void print2(struct S* ps)
{printf(%d\n, ps-num);printf(%d\n, ps-data[0]);printf(%d\n, ps-data[1]);printf(%d\n, ps-data[2]);
}
int main()
{print1(s); //传结构体变量printf(_________);print2(s); //传地址return 0;
}
两种调用传参的结果都是一样的 但是还是用printf2来传地址时更好 函数传参的时候参数是需要压栈会有时间和空间上的系统开销。 如果传递一个结构体对象的时候 结构体过大参数压栈的的系统开销比较大 所以会导致性能的下降 二.结构体内存对齐 struct S1 { char c1 ; int i ; char c2 ; }; 这个结构体有多大呢 第一反应大抵是1416吧 但其实 1.对其规则 1. 第一个成员在与结构体变量偏移量为 0 的地址处。 2. 其他成员变量要对齐到某个数字对齐数的整数倍的地址处。 对齐数 编译器默认的一个对齐数 与 该成员大小的 较小值 。 VS中默认的值为8 3. 结构体 总大小为最大对齐数每个成员变量都有一个对齐数的整数倍 。 4. 如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍。 按照对其规则这是上述答案的分析
接下来再看另外一个例子
eg
struct S2
{char c1;char c2;int i;
};int main()
{printf(%d, sizeof(struct S2));return 0;
} 答案便是 2.存在原因 结构体的内存对齐是拿空间来换取时间的做法 一些资料也显示说
访问效率内存对齐可以使结构体的成员在内存中连续存储减少内存访问次数提高访问效率。如果结构体成员没有进行内存对齐可能会导致成员之间存在空隙需要多次访问内存才能获取到所有成员的值数据对齐某些硬件平台要求访问特定类型的数据必须按照特定字节对齐否则可能会导致访问错误或性能下降。例如某些处理器要求访问双字节数据如short类型必须按2字节对齐访问四字节数据如int类型必须按4字节对齐。如果结构体成员没有进行内存对齐可能会导致访问错误或性能下降 3.减少浪费
那我们如何尽量减少内存对齐所产生的浪费呢 让占用 空间小的成员尽量集中 在一起 所以上述S1的例子我们可以改造成
struct S1
{char c1;int i;char c2;
};
struct S2
{char c1;char c2;int i;
};
int main()
{printf(%d\n, sizeof(struct S1));printf(%d, sizeof(struct S2));return 0;
}
结果也确实减小了内存使用 4.修改默认对齐数 这里我们使用#pragma可以改变我们的默认对齐数 #pragma pack(8)//设置默认对齐数为8
struct S1
{char c1;int i;char c2;
};#pragma pack()//取消设置的默认对齐数还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{char c1;int i;char c2;
};int main()
{printf(%d\n, sizeof(struct S1));printf(%d, sizeof(struct S2));return 0;
}
这次S2的大小便是我们最初认为的6了 三.位段
1.什么是位段 位段的声明和结构是类似的有两个不同 位段的成员必须是 int、unsigned int 或signed int 。 位段的成员名后边有一个冒号和一个数字 struct A {int a : 2; //a占用2个bit位int b : 5; //b占用5个bit位int c : 10;int d : 30;
};int main()
{struct A a;printf(%d, sizeof(a));
}
不使用位段的话是占16个字节现在是 2.位段的内存分配
位段的成员可以是 int unsigned int signed int 或者是 char 属于整形家族类型 位段的空间上是按照需要以4个字节 int 或者1个字节 char 的方式来开辟的一次增加4/1个字节位段涉及很多不确定因素位段是不跨平台的注重可移植的程序应该避免使用位段 struct S
{char a : 3;char b : 4;char c : 5;char d : 4;
};int main()
{struct S s { 0 };s.a 10;s.b 12;s.c 3;s.d 4;return 0;
} 3.位段的跨平台问题
int 位段被当成有符号数还是无符号数是不确定的。 位段中最大位的数目不能确定。16位机器最大1632位机器最大32写成27在16位机器会出问题。 位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义。 当一个结构包含两个位段第二个位段成员比较大无法容纳于第一个位段剩余的位时是 舍弃剩余的位还是利用这是不确定 这次关于结构体相关的内容就先到这里啦 在下一篇文章中我们将详细介绍枚举和联合体的内容。感谢大家的支持加油