详解结构体

简介: 详解结构体

结构体

为什么要创建结构体类型?在我们处理复杂对象的时候,比如描述一个人的时候,它有名字,性别,身高,体重等一些方面的特征。用结构体打包描述的时候就比较方便。

结构体类型的声明

结构体类型的关键字struct

声明的基本模板为:

struct 标签
{

成员;
}变量;

结构体的成员可以是不同的类型。

结构体类型的特殊声明:

匿名结构体类型,它只能使用一次。

struct
{
  int a;
  char b;
}x;
struct
{
  int a;
  char b;
}*p;

p=&x这样写是错误的,在编译器看来,它们俩是不同的类型。

看下面这两种:

struct
{
  int a;
  int b;
}x;
这里的x是一个结构体类型的全局变量
typedef struct
{
  int a;
  int b;
}x;
这里的x是结构体类型。
typedef struct stu
{
  int a;
  int b;
}*put,stu;
这里的put等价于struct stu*类型
stu等价于struct stu类型

结构的自引用

例如:

typedef struct node
{
  int x;
  struct node* p;
}node;
这个自引用就是正确的。
typedef struct node
{
  int x;
  node* p;
}node;
这种就是错误的,这个问题的出现就和先有鸡还是先有蛋的问题一样。
不能知道是先重命名了还是先创建的。

结构体变量的定义和初始化

  • 结构体变量的定义
struct student
{
  char name[20];
  int age;
}a,b;
//这种是一边声明,一边定义变量的,这里的变量a,b为全局变量
struct student c;
//这种定义的变量是全局变量
int main()
{
  struct student d;
  //这里的d为局部变量
  return 0;
}
  • 简单的初始一下:(应该没有难道吧)
struct student
{
  char name[20];
  int age;
}a={"zhangshan",20}, b={"wuanwu",18};
struct student c={"hh",0};
int main()
{
  struct student d={"sb",88};
  return 0;
}

🟥结构体内存对齐

如何计算结构体的大小,就需要知道它在内存中是如何储存的。

而结构体在内存中存在结构体对齐的现象。

1.第一个成员变量放在偏移量为0的位置

2.后面的成员放在偏移量为对齐数的整数倍的位置。

3.对齐数:编译器默认的一个对齐数与成员大小的较小值

vs的默认对齐数位8

4.结构体的总大小为每个成员默认最大对齐数的整数倍。

5.如果含有结构体嵌套的情况,镶嵌的那个结构体的对齐数是里面成员的最大对齐数。

  • 下面仔细讲解一下:
  struct S1
  {
    char c1;
    int i;
    char c2;
  };
  printf("%d\n", sizeof(struct S1));

  struct S2
  {
    char c1;
    char c2;
    int i;
  };
  printf("%d\n", sizeof(struct S2));

  struct S3
  {
    double d;
    char c;
    int i;
  };
  printf("%d\n", sizeof(struct S3));

  struct S4
  {
    char c1;
    struct S3 s3;
    double d;
  };
  printf("%d\n", sizeof(struct S4));

按上面的分析:可知结构体的大小分别为:12,8,16,32

运行看一下情况:

修改默认对齐数

我们用pragma修改默认对齐数

例子:

#pragma pack(4)
//这里面的数字表示的是默认对齐数
struct p
{
  int a;
  int b;
  char c;
};
#pragma pack()

结构体传参

在结构体传参的时候,最好选择传址调用,有两个好处

1.可以减少对空间的浪费

2.可以对里面的数据进行修改

简单的例子:

#include <stdio.h>
struct student
{
  char name[20];
  int age;
};
void f(struct student* p)
{

}
int main()
{
  struct student p;
  f(&p);
  return 0;
}

结构体实现位段

位段的实现和结构体类似,只不过位段的成员的类型只能是

unsigned int 或者int类型,char类型的也可以。

每个成员名后面要加上:和数字

举个简单的例子:

struct stu
{
  int a : 4;
  int b : 2;
};

后面的数字表示bite位。位段不存在对齐。

位段不具有跨平台性:

1.位段中没有规定在内存使用的过程中,是从左使用还是从右使用。

2.不能满足下一个成员使用的空间是舍弃还是保留的问题没有规定。

3.int位段中无符号还是有符号的问题没有规定

结构体实现位段的内存分配

struct S
{
  char a : 3;
  char b : 4;
  char c : 5;
  char d : 4;
};
struct S s = { 0 };
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

枚举

枚举类型的关键字为enum,枚举就是把所有的可能列举出来。

里面的叫做枚举常量。它们也是有值的,如果没有给他们初始化。默认第一个是0,后面的依次增加。

例子:

enum colour
{
  //注意后面是逗号,
  red,//值是0
  yellow,//值是1
  green//值是2
};


enum colour
{
  red=2,//这种不是赋值,而是给这个常量一个初始值。
  yellow=5,
  green//它的值为6
};

联合(共用体)

联合类型的定义

关键字union

里面的成员都是占用同一块空间。

例子:

union people
{
  char a;
  int b;
};

联合大小的计算

联合体可能是最大类型所占空间的大小。

当结构体的大小不是最大对齐数的整数倍时,需要对齐。

例子:

union Un1
{
  char c[5];
  //开辟了5个字节的空间
  int i;
  //i占4个大小的空间,开辟的空间够用
  //共5个字节的空间,但是不是4的整数倍,存在内存对齐,
  //最终为8个字节的大小
};
union Un2
{
  short c[7];
  int i;
  //开辟的14个字节的空间也不是4的整数倍,需要对齐。
  //最终的大小为16个字节
};
int main()
{
  printf("%d\n", sizeof(union Un1));
  printf("%d\n", sizeof(union Un2));
  return 0;
}

看结果:

相关文章
【结构体】
【结构体】
29 0
|
存储 C语言
C 结构体
C 结构体。
35 0
|
6月前
|
存储 算法 数据安全/隐私保护
结构体
结构体
61 1
|
5月前
|
编译器 Linux C语言
浅谈结构体
浅谈结构体
42 1
|
6月前
|
存储 算法 C语言
c结构体
c结构体
35 1
|
6月前
|
编译器 Linux C语言
结构体(详解)
结构体(详解)
64 1
|
6月前
|
算法 程序员 C++
|
机器学习/深度学习 存储 编译器
Day_16 结构体
Day_16 结构体
|
6月前
|
Java 编译器 Linux
再次认识结构体
再次认识结构体
71 0
|
编译器