C语言自定义类型超详细梳理之结构体 枚举 联合体
一、什么是结构体
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
//结构体声明 struct tag //struct:结构体关键字,tag:标签名,合起来是结构体类型(类型名) { member - list;//大括号里面的是结构体成员变量 }variable - list;//结构体变量
1.结构体实现
代码如下:
#include<stdio.h> struct Book { char name[20];//书名 int price;//价格 char id[20];//书号 }b2,b3,b4;//结构体变量(全局变量) int main() { //结构体变量(局部变量) struct Book b1 = { "c和指针", 30, "1112345454" };//结构体初始化 struct Book* pb = &b1; printf("%s %d %s\n",b1.name,b1.price,b1.id ); printf("%s %d %s\n", pb->name, pb->price, pb->id);//指针方式打印 return 0; }
2.匿名结构体类型
//匿名结构体类型 struct { int a; char b; float c; }s;//直接永匿名结构体类型创建了一个变量s,匿名结构体只能用一次 struct { int a; char b; float c; }*ps;//匿名结构体的指针 结构在声明的时候省略掉了结构体标签(tag)就叫做匿名结构体。 那么问题来了? int main() { ps = &s;//不合法,编译器会把上面的两个声明当成完全不同的两个类型。 所以是非法的 }
3.结构体自引用
struct Node { int data; struct Node* next; } //结构体自引用 //这个节点能够找到同类型的下一个节点,这就叫结构体的自引用,我自己能找到同类型跟自己同类型的下一个元素就叫结构体的自引用。 //结构体的自引用实现:在结构体里面包含同类型的结构体的指针。
4.结构体的内存对齐
首先得掌握结构体的对齐规则:
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
我们来算一下上面结构体S内存大小为什么是12个字节
我用到编译器是vs,vs编译器的默认对齐数是8.
1.结构体的第一个成员,放在结构体变量在内存中储存位置的0偏移处开始。
2.从第二个成员往后的所有成员,都放在一个对齐数(成员的大小和默认对齐数的较小值)的整数的整数倍的地址处。
3.结构体的总大小是结构体的所有成员的对齐数中最大的那个对齐数的整数倍。
5.结构体位段
位段的声明和结构是类似的,有两个不同:
1.位段的成员必须是 int、unsigned int 或signed int 。
2.位段的成员名后边有一个冒号和一个数字。
假设我们用二进制的方式来表示性别,分为男、女、保密。可以用00、01、10分别表示。这样我们连一个字节的大小都用不到,但如果我们创建变量,一个int变量就占四个字节,所以说位段在一定程度上节省了空间。
位段的内存分配
1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
二、什么是枚举
性别有:男、女、保密,也可以一一列举。
月份有12个月,也可以一一列举
这里就可以使用枚举了。
枚举是要创造出一种新的类型,这种类型的取值是非常有限的,明确的只有那么几种可能取值,我们就可以用枚举来创造一个枚举类型
枚举类型的大小就是4.
1.枚举类型的定义
#include<stdio.h> //声明枚举类型 enum Color//enum枚举关键字,Color枚举类型, { RED,//大括号里面放的是枚举的可能取值(常量) GREEN, BLUE }; int main() { enum Color c = BLUE; return 0; }
大括号里面这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。
enum Color//颜色 { RED=1, GREEN=2, BLUE=4 };
2.枚举的优点
我们可以使用 #define 定义常量,为什么非要使用枚举?
枚举的优点:
1. 增加代码的可读性和可维护性
2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
3. 防止了命名污染(封装)
4. 便于调试
5. 使用方便,一次可以定义多个常量
三、联合(共用体)
1.什么是联合(共用体)
联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。
2.联合(共用体)的定义
//联合类型的声明 union Un { char c; int i; }; //联合变量的定义 union Un un; //计算连个变量的大小 printf("%d\n", sizeof(un));
计算联合(共用体)的大小
这里为什么算出的结果是4呢,我们看下图:
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联 合至少得有能力保存最大的那个成员)。
3.联合(共用体)的初始化
#include<stdio.h> union Un { char c; int i; }; int main() { union Un u = { 10 };//初始化 u.i = 1000;//成员变量单独初始化 u.c = 100; printf("%p\n",&u ); printf("%p\n", &(u.c)); printf("%p\n", &(u.i)); return 0; }
总结
这样就简单介绍完了结构体,枚举和联合体的定义,初始化,和简单的使用。写的比较潦草,如果上述文章有任何问题 ,欢迎大佬们提出质疑,我会虚心学习和改正,最重要的是能共同进步,共同成长,学习好编程。
栏 目:C代码
本文地址:http://www.codeinn.net/misctech/209007.html