自定义类型:那些容易出错的地方

本讲主要内容

目录

 1.结构体 

 2.位段

3.枚举

4.联合体(共用体)


1.结构体

1.1特殊的声明:匿名结构体声明

//匿名结构体
struct {
	int a;
	int b;
	char arr[10];
}x;
 
struct {
	int c;
	int m;
	char arr1[10];
}*p;

上面的代码段定义了两个匿名结构体,但是编译器认为上面的两个结构体是不同的类型

所以下面这段代码是非法的

*p=&x;

1.2结构体的自引用

同类型找到同类型的节点的写法是错误的

struct stu 
{
  int a;
  char b;
  struct stu n
};

原因:向上图对结构体进行自引用会使函数无限嵌套下去,会消耗极大的内存

正确的用法

struct stu
{
   int a;
   char b;
  //上面被称为数据域
   struct stu *p
  //指针域
};

指针只占4/8个字节的内存,而且能够找到下一个节点

结构体自引用不能省略名字

typedef struct 
{
  int a;
  char b;
  struct node *n
}node;

这里把一个匿名结构体重命名为node,为什么上图的做法是非法的呢?

因为在结构体指针=出现了node,而在之前并没有对node进行命名,所以会报错,如何修改

typedef struct node
{
  int a;
  char b;
node* n
}node;

先把匿名结构体命名为node,在用结构体指针进行自引用,所以,当我们对结构体进行传参的时候,传的都是结构体的地址,而不是结构体(&结构体变量名)

1.3结构体的内存对齐

结构体内存对齐是结构体的最大难点,根据结构体的对齐规则对结构体进行内存大小的计算

规则:自定义类型:那些容易出错的地方_第1张图片

struct stu 
{
  int a;
  double b;
  int c;
};

 如何计算上图中结构体的大小

根据规则画出内存图自定义类型:那些容易出错的地方_第2张图片

总的来说,结构体的内存是拿空间换取时间的做法;

如果想更加节省空间,可以让空间小的成员尽量集中在一起。

 2.位段

什么是位段?

位段的声明和结构体类型,有两点不同

1.位段的成员必须是int,unsigned int这一种,或者char

2.位段的成员名后面必须要有一个冒号和数字


struct A
{
	int a : 2;
	int b : 10;
	int c : 30;
};

A就是一个位段类型,在32为编译器条件下,单个成员的位段不能大于32,上图中的2,10,30指的都是二进制位的意思;

这个位段的大小怎么求呢?

位段是一次开辟一个int型,即一次开辟四个字节,如果是char,就一次开辟一个字节,

所以a和b一共占了12个二进制位,但是c需要30个二进制位,所以要重新开辟4个字节,所以,该位段多占大小是8个字节

3.枚举的易错点

enum color//枚举类型
{
   RED,//枚举常量
   GREEN,
   WHITE,
};

RED是默认为·,一次递增1,当然可以对枚举常量进行赋值。

枚举的优点:1.增加代码的可读性和可维护性

                      2.使用方便,一次可以定义多个变量

                     3.防止命名污染

                     4.便于调试

                     5.和#define对比有类型检查,更加严谨

枚举的赋值:只能那枚举的常量给枚举的变量赋值

enum color
{
  red=1,
  white=10,
  black=15,
}

enum color red=white;//这样赋值是正确的
white=10;//非法

4.联合体(共用体)

为什么叫联合体?

一位联合体成员都共用同一块内存

4.1联合体的大小怎么确定?

规则:当最大成员大小不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍;

自定义类型:那些容易出错的地方_第3张图片

 

 

你可能感兴趣的