c语言学习第二十九课——自定义类型:结构体与枚举

简介: c语言学习第二十九课——自定义类型:结构体与枚举

结构体

结构体的的声明:

struct tag
{
  member-list;  //结构体成员列表
}variable-list;  //变量列表

这里举例定义一个学生类型的结构体

struct Stu
{
  //成员变量
  char name[20];
  int age;
  int weight;
}s3,s4,s5;//也可以直接创建,这里是全局变量
int main  ()
{
  struct Stu s1;//创建结构体变量 
  struct Stu s2;//这里是局部变量
  return 0;
}

匿名结构体类型

struct   //结构体名,省略掉。
{
  char cl;
  int b;
  double d;
}s1;
struct   
{
  char cl;
  int b;
  double d;
}*p;    //结构体的指针变量

在这里,p = &s1;会报错,类型不兼容。其次建议不要使用该种写法,一次性用品结构体,无法创建新的结构体变量

结构的自引用

在数据结构中,描述数据在内存的存储结构,顺序表,单链表都是线性结构,二叉树,树结构

当一个结构体要包含一个自己一样的结构体,

struct Node//可确定结构体大小
{
  int data;
  struct Node* next;
};

这里只能用该结构体去包含自己的指针,不能直接在结构体在创建本身。

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

struct S
{
  int a;
  char c;
}s1;
struct B
{
  float a;
  struct S s;
};
int main()
{
  int arr[10] = {1,2,3};
  struct S s2 = { 100,'q' };
  struct  B sb = { 3.14f,{200,'w'} };//浮点数精确保存
  printf("%f,%d,%c", sb.a, sb.s.c);
  return 0;
}

定义指针类型的

struct S
{
  char name[20];
  int* ptr;
};
int main()
{
  struct S a = { "ABXDEF",NULL };//&+变量
  return 0;
}

结构体的大小

先举例

struct s1
{
  int a;
  char c;
};
struct s2
{
    char c;
  int a;
  char d;
};
struct s3
{
  int a;
  char c;
  char d;
  char e;
};
int main()
{
  printf("%d", sizeof(struct s1));//8
  printf("%d", sizeof(struct s2));//12
  printf("%d", sizeof(struct s3));//12
  return 0;
}

为什么会是这样呢?这里需要求了解关于结构体内存是对齐的知识。先了解结构体是怎样在内存中存放的。

存放规则  1.每一个字节相对起始位置都有一个偏移量,结构体的第一个成员永远被放在0偏移处,对齐数假设从0开始往后。

2.从第二个成员开始,以后每个成员都要对齐到某个对齐数的整数倍数。这个对齐数是:成员自生身大小和默认对齐数中的较小值 备注 vs环境下是8,gcc下没有,默认为自身大小为对齐数。

3.结构体的总大小必须是,所有成员对齐数中最大对其数的整数倍,如果不是,则浪费空间使对齐。

这里举例  struct s2

从这里可以看出,结构体成员的定义顺序会影响其在内存的存放方式

struct _s2
{
  char c;
  char d;
    int  a;
};


787b30064cd94df082d03e230ecf6d0d.png

第四条规则:如果嵌套了结构体,则该结构体只能放在自身最大对其数的整数倍的位置上,整个结构体的大小必须是最大对齐数的整数倍(包含嵌套结构体中最大的对其数)。

struct s3
{
  int a;
  char c;
  char d;
  char e;
  struct s1 s;
};
int main()
{
  printf("%d", sizeof(struct s3));//16
  return 0;
}

设计结构体时,既要满足对齐,又要节省空间

这里提供了可以修改默认对齐数

#pragma pack(8);设置默认对齐数为8

offsetof宏,求该成员与上一个成员的偏移量.

结构体传参

void print2(const struct s* ps)
{
  printf("%d", ps->num);
}

结构体实现的位段

位段的声明和结构是类似的,位段的成员通常为int unsigned int,位段的成员名后边有一个和一个数字

位段表示的意义:给一定的大小空间,结构体成员认为是足够的。

struct A
{
  int _a : 2;//2个比特
  int _b : 5;
  int _c : 10;
  int _d : 30;
};
int main()
{
  struct A sa = { 0 };
  printf("%d\n", sizeof(sa));//8个字节
  return 0;
}

不同的编译器,位段是不一样的。在vs中

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;
}

1.分配的内存中比特位是从右向左使用,

2.分配的内存空间不够成员使用时,浪费掉。

  位段是不跨平台的位段的成员可以是 int 、unsigned int、 signed int 或者是 char (属于整型家族)类型

位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。

位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

枚举

顾名思义。就是列举。把可能的取值一一列举。如星期几,性别等,枚举的用法简单,这里不做赘述。

枚举类型的定义

enum Day
{
  Mon=1,
  Tuse,
  Thus,
  wentu,//枚举常量,可以赋值
  frid,
};
int main()
{
  enum  Day day1 = Mon;
  printf("%d\n", Mon);//打印直接打印
  return 0;
}

枚举可以使代码的可读性增加,便于调试。可定义多个常量。

相关文章
|
1天前
|
编译器 程序员 Linux
【C语言篇】结构体和位段详细介绍
跟结构相⽐,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。
|
1天前
|
存储 编译器 C语言
【C语言篇】自定义类型:联合体和枚举详细介绍
像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。
|
12天前
|
存储 安全 编译器
C语言自定义类型
C语言自定义类型
22 10
|
6天前
|
存储 C语言
C语言------结构体和共用体
这篇文章是关于C语言中结构体和共用体的实训,通过示例代码演示了结构体的定义、赋值、使用,以及如何使用结构体变量进行数据的组织和操作,包括输入、排序、求平均分和查找学生信息等功能。
C语言------结构体和共用体
|
11天前
|
编译器 C语言
C语言函数的学习
掌握函数的使用是学习C语言的关键一环,理解和应用这些基本的函数概念将使你能够更有效地利用C语言的强大功能。
8 0
|
1月前
|
存储 编译器 定位技术
结构体数组在C语言中的应用与优化策略
结构体数组在C语言中的应用与优化策略
|
1月前
|
存储 编译器 数据库
结构体数组在C语言中的应用与优化技巧
结构体数组在C语言中的应用与优化技巧
|
6天前
|
存储 C语言
【C语言函数】static和extern关键字修饰
【C语言函数】static和extern关键字修饰
|
1天前
|
编译器 程序员 C语言
【C语言篇】从零带你全面了解函数(包括隐式声明等)(下篇)
⼀般情况下,企业中我们写代码时候,代码可能⽐较多,不会将所有的代码都放在⼀个⽂件中;我们往往会根据程序的功能,将代码拆分放在多个⽂件中。
|
21小时前
|
C语言
【C语言】字符串及其函数速览
【C语言】字符串及其函数速览
11 4