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

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

相关文章
|
22天前
|
存储 C语言
如何在 C 语言中实现结构体的深拷贝
在C语言中实现结构体的深拷贝,需要手动分配内存并逐个复制成员变量,确保新结构体与原结构体完全独立,避免浅拷贝导致的数据共享问题。具体方法包括使用 `malloc` 分配内存和 `memcpy` 或手动赋值。
30 10
|
21天前
|
安全 编译器 Linux
【c语言】轻松拿捏自定义类型
本文介绍了C语言中的三种自定义类型:结构体、联合体和枚举类型。结构体可以包含多个不同类型的成员,支持自引用和内存对齐。联合体的所有成员共享同一块内存,适用于判断机器的大小端。枚举类型用于列举固定值,增加代码的可读性和安全性。文中详细讲解了每种类型的声明、特点和使用方法,并提供了示例代码。
19 3
|
21天前
|
存储 大数据 编译器
C语言:结构体对齐规则
C语言中,结构体对齐规则是指编译器为了提高数据访问效率,会根据成员变量的类型对结构体中的成员进行内存对齐。通常遵循编译器默认的对齐方式或使用特定的对齐指令来优化结构体布局,以减少内存浪费并提升性能。
|
26天前
|
编译器 C语言
共用体和结构体在 C 语言中的优先级是怎样的
在C语言中,共用体(union)和结构体(struct)的优先级相同,它们都是用户自定义的数据类型,用于组合不同类型的数据。但是,共用体中的所有成员共享同一段内存,而结构体中的成员各自占用独立的内存空间。
|
26天前
|
存储 C语言
C语言:结构体与共用体的区别
C语言中,结构体(struct)和共用体(union)都用于组合不同类型的数据,但使用方式不同。结构体为每个成员分配独立的内存空间,而共用体的所有成员共享同一段内存,节省空间但需谨慎使用。
|
30天前
|
编译器 C语言 C++
C语言结构体
C语言结构体
25 5
|
存储 C语言
【C语言】 条件操作符 -- 逗号表达式 -- []下标访问操作符,()函数调用操作符 -- 常见关键字 -- 指针 -- 结构体
【C语言】 条件操作符 -- 逗号表达式 -- []下标访问操作符,()函数调用操作符 -- 常见关键字 -- 指针 -- 结构体
【C语言】——define和指针与结构体初识
【C语言】——define和指针与结构体初识
|
存储 C语言
C语言初识-关键字-操作符-指针-结构体
C语言初识-关键字-操作符-指针-结构体
63 0
【C语言】指针,结构体,链表
【C语言】指针,结构体,链表