首页 > 其他分享 >零基础非科班也能掌握的C语言知识18 自定义类型

零基础非科班也能掌握的C语言知识18 自定义类型

时间:2024-06-07 16:29:22浏览次数:13  
标签:位段 自定义 int 18 成员 C语言 char 枚举 结构

自定义类型

1.结构体

C语⾔已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类型还是不够的,假设我想描述学⽣,描述⼀本书,这时单⼀的内置类型是不⾏的。
描述⼀个学⽣需要名字、年龄、学号、⾝⾼、体重等;
描述⼀本书需要作者、出版社、定价等。C语⾔为了解决这个问题,增加了结构体这种⾃定义的数据类型,让程序员可以⾃⼰创造适合的类型。
结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如:标量、数组、指针,甚⾄是其他结构体。

1.1结构的声明

在这里插入图片描述

//描述一个学生
struct Stu
{
char name[20];//描述名字
int age;//描述年龄
char sex[5];//描述性别
char id[20];//描述学号
};//这个不能丢

1.2结构体变量的创建和初始化

1.2.1普通声明

在这里插入图片描述

1.2.2 嵌套声明

在这里插入图片描述
直接在分号后创建变量并初始化

1.2.3 不完全声明(匿名结构体)

在这里插入图片描述
适用于只使用一次的结构体

1.3结构成员访问操作符

1.3.1结构体成员的直接访问

在这里插入图片描述

1.3.2结构体成员的间接访问

在这里插入图片描述

1.4结构体的自引用

我们将一系列数据存在内存中,不管我们以何种方式存储都必须做到能找到第一个数据和下一个数据,因此我们定义一个结构体能找到第一个数据且能找到下一个数据的地址

struct Node
{
int data;
struct Node* next;
};

在结构体⾃引⽤使⽤的过程中,往往夹杂了 typedef 对匿名结构体类型重命名
在这里插入图片描述

1.5结构体内存对齐

计算结构体的内存大小

1.5.1对齐规则

在这里插入图片描述
注意:当成员变量为数组时,它的对齐数取决于数组中存放的变量类型也就是说char[5]的对齐数为1而不是5
练习(vs平台下)
在这里插入图片描述
偏移量为0的位置是任何对齐数的0倍
在这里插入图片描述
结构体struct S4的大小大家可以自己画表格尝试一下,同时提供给大家一个求偏移量的函数
offsetof(结构体,成员);

1.5.2为什么存在内存对齐

在这里插入图片描述
那我们如何节约内存空间呢,只要让占用空间小的变量集中在一起就行了(而顺序是是不做要求的也就是说两个char类型的变量和两个int类型的变量,只要char紧挨着就行另外的就不用考虑了)

struct S1
{
char a;
char b;
int c;
int d;
};
struct S2
{
int c;
char a;
char b;
int d;
};
struct S3
{
int c;
int d;
char a;
char b;
};

这四者大小相同

1.5.3 修改默认对齐数

在这里插入图片描述
由实现定义,可能要跟硬件相匹配。

1.6结构体传参

在这里插入图片描述
我们往往倾向于print2
在这里插入图片描述

1.7结构体实现位段

1.7.1什么是位段

在这里插入图片描述
那我们接下来得先了解位段的内存分配

1.7.2位段的内存分配

在VS平台上

  • 位段的空间上按照需要以4个字节(int)或者一个字节(char)来开辟的,空间是由右向左去利用的
  • 当剩下的空间存放不下下一个成员时,剩下的空间会被浪费
    例子:
    在这里插入图片描述
    在这里插入图片描述
    未上色的是未利用或舍弃的
    在这里插入图片描述
    结果和分析的答案一样
    在这里插入图片描述
    大家可以自己算一下这个在内存中的存储
    注意:一个int可以放32个比特位,_a占用2个,_b占用5个,_c占用10个,共使用17个,然后_d放不进去,所以要放在第二个基本类型中。也就是说int要去浪费空间是从四个字节来看,注意这一点
    在这里插入图片描述
    可以尝试一下

1.7.3位段的跨平台问题

在这里插入图片描述
大家可以看到上面是如何分析的,不同编译器可能不同。因为标准C并没有定义,但是大家可以通过调试去验证

1.7.4位段的应用

在这里插入图片描述

1.7.5 位段使用的注意事项

位段的⼏个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的bit位是没有地址的。所以不能对位段的成员使⽤&操作符,这样就不能使⽤scanf直接给位段的成员输⼊值,只能是先输⼊放在⼀个变量中,然后赋值给位段的成员。

2.联合体

2.1 联合体类型的声明

像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。
但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫:共⽤体。
给联合体其中⼀个成员赋值,其他成员的值也跟着变化。

2.2联合体的特点

联合的成员是共⽤同⼀块内存空间的,这样⼀个联合变量的⼤⼩,⾄少是最⼤成员的⼤⼩(因为联合⾄少得有能⼒保存最⼤的那个成员)。
在这里插入图片描述
在这里插入图片描述

2.3联合体大小的计算

在这里插入图片描述
正如我前面强调数组的对齐数取决于数组的元素,Un1的大小为最大成员的大小也就是5,但5不是最大对齐数int 4的倍数,浪费三个空间,联合体的大小为八个字节。Un2大家自己试试
使⽤联合体是可以节省空间的,举例:
⽐如,我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。
每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。
图书:书名、作者、⻚数
杯⼦:设计
衬衫:设计、可选颜⾊、可选尺⼨
那我们不耐⼼思考,直接写出⼀下结构:
我们注意到:三件商品都有库存量、价格、商品类型(要重复使用),书名、作者、⻚数(独有只使用一次),同理
故所以我们就可以把公共属性单独写出来,剩余属于各种商品本⾝的属性使⽤联合体起来,这样就可以介绍所需的内存空间,⼀定程度上节省了内存。

struct gift_list
{
 int stock_number;//库存量 
 double price; //定价 
 int item_type;//商品类型 
 
 union {
 struct
 {
 char title[20];//书名 
 char author[20];//作者 
 int num_pages;//⻚数 
 }book;
 struct
 {
 char design[30];//设计 
 }mug;
 struct 
 {
 char design[30];//设计 
 int colors;//颜⾊ 
 int sizes;//尺⼨ 
 }shirt;
 }item;
};

这里union和struct都采用了匿名声明,因为独有的我们仅仅使用一次

3.枚举类型

3.1枚举类型的声明

枚举顾名思义就是⼀⼀列举。
把可能的取值⼀⼀列举。
⽐如我们现实⽣活中:
⼀周的星期⼀到星期⽇是有限的7天,可以⼀⼀列举
性别有:男、⼥、保密,也可以⼀⼀列举
⽉份有12个⽉,也可以⼀⼀列举
三原⾊,也是可以意义列举
这些数据的表⽰就可以使⽤枚举了
在这里插入图片描述

3.2枚举类型的特点

在这里插入图片描述

3.3 枚举类型的使⽤

#include<stdio.h>
typedef enum
{
	FALSE,
	TRUE
}Bool;
int main()
{
	Bool a = TRUE;
		if (a)
			printf("真");
	return 0;
}

枚举是用来稀疏地掩饰整数的因为往往我们不会把数字与字符串对应起来,枚举解决来这一点。
虽然把枚举的值(字符串)作为整数使用非常方便,但是把整数用作枚举的值却是非常危险的。我们往往通过枚举枚举常量给枚举赋值
也就是Bool a=TRUE;尽管C语言上并没有在这要求,但是C++上不允许整数作为枚举的值来使用,因此我们这里最好统一。

标签:位段,自定义,int,18,成员,C语言,char,枚举,结构
From: https://blog.csdn.net/Yusei_0523/article/details/139487181

相关文章

  • 2032:【例4.18】分解质因数
    2032:【例4.18】分解质因数时间限制:1000ms      内存限制:65536KB提交数:41561   通过数: 26559【题目描述】把一个合数分解成若干个质因数乘积的形式(即求质因数的过程)叫做分解质因数。分解质因数(也称分解素因数)只针对合数。输入一个正整数<spanid="......
  • 实验6_C语言结构体、枚举应用编程
    实验任务4#include<stdio.h>#defineN10typedefstruct{charisbn[20];//isbn号charname[80];//书名charauthor[80];//作者doublesales_price;//售价intsales_count;//销售册数}Book;voi......
  • 6.C语言scanf及其他输入知识点
    C语言scanf相关用法及其他输入1—scanf输入的用法2—scanf注意的问题3—其他输入1—scanf输入的用法程序#include"stdio.h"intmain(){ intdata; intdata2; intdata3; printf("输入一个整数:\n"); scanf("%d",&data); printf("输入完毕\n"); printf(......
  • 获取自定义 HTML 开头标记和结尾标记之间的文本
    $data="<Data>hello</Data>";preg_match_all("/\<Data\>[.]+\<\/Data\>/",$data,$match);print_r($match);返回:Array([0]=>Array())Array([0]=>Array())所以我猜没有匹配到?你是对的,你的正则表达式没有匹配......
  • C语言基础——函数
             ʕ•ᴥ•ʔ       づ♡ど ......
  • C语言入门 第三章 数据和变量
    目录3.1数据3.1.1整数3.1.2浮点数3.2变量与常量3.2.1定义变量 3.2.2变量分类3.2.3变量的作用域与生命周期 3.2.4常量 3.3基本数据类型 3.3.1int类型 3.3.2其他整数类型3.3.3char类型3.3.4_Bool类型 3.3.5float、double和longdouble类型 3.......
  • vue2使用Clodop插件打印表格,分页,每页显示页头页尾,自定义纸张大小
    一、前往lodop官网,下载插件,下载中心-Lodop和C-Lodop官网主站 这里下载的window64位的,将插件安装好,运行,会看到引入项目第一种、可以直接将script标签放入vue的head中,在项目运行时自动加载。第二种、也可以将js文件下载至本地,通过import引入,前提是将CLODOP对象export出......
  • 618火热来袭,网络安全书单推荐
    随着数字化浪潮的汹涌澎湃,网络安全已经成为了每个从业者不可回避的重要议题。在这个信息泄露和网络攻击层出不穷的时代,网络安全不仅仅是一份工作,更是一种责任、一种使命。为了帮助大家更好地装备自己,迎接各种安全挑战,我们精心挑选了以下网络安全书籍,每本都是市面上的佳作,助......
  • Android 13.0 hal层关于新增自定义hal模块功能实现
    1.前言在13.0的系统rom定制化开发中,在对hal模块进行开发时,需要通过添加自定义的hal模块来实现某些功能时,就需要添加hal模块的相关功能,接下来就来实现一个案例来供参考接下来就来具体实现这个功能2.hal层关于新增自定义hal模块功能实现的核心类hardware\interfaces\3.ha......
  • 九、C语言:隐式类型转换(整型提升与算数转换)
    一、隐式类型转换C的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。二、整型提升//1.表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作......