广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言自定义类型全解析
  • 498
分享到

C语言自定义类型全解析

2024-04-02 19:04:59 498人浏览 八月长安
摘要

目录前言结构体类型结构体的声明结构体变量的定义与初始化结构体的自引用结构体的访问结构体的传参传结构体传地址结构体的内存对齐(强烈建议观看)位段位段的声明位段的内存管理位段的跨平台性 

前言

初学C语言

我们先接触的都是内置的类型

比如说int char short float double long等等

这一期就来聊一聊自定义类型的知识

结构体类型

首先我们要知道什么是结构体

结构体就是各种值集合

这些值被称作结构体成员,这些成员可包括各种不同的类型


struct tag         //这里的struct是结构体的关键字,tag是结构体标签,也就是结构体的名称
{
	number - list; //结构体成员列表
}veriable-list;    //结构体的变量 

结构体的声明

如果结构体的标签是student,我拿student来举例子

结构体的完整声明


struct Student
{
    char name[20];//姓名
    char sex;//性别
    int age;//年龄
    int num;//学号
};   //这里的分号不能丢

结构体的不完全声明(匿名结构体类型)


struct
{
	int a;
	char b;
	double c;
}s;   //这s不能省略

匿名结构体的特点就是没有结构体标签

但这样写用户使用时只能使用一次,也就是说只能在结构体声明时就定义变量

因为你找不到结构体标签,就相当于找不到门牌号一样,无法再对其定义一个变量

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

结构体的定义大致分为三种情况

<1>结构体声明的同时定义


struct Student 
{
    char name[20];//姓名
    char sex[20];//性别
    int age;//年龄
}s={"zhangsan","nan",20};

<2>结构体先声明,再定义


#include<stdio.h>
struct Student
{
    char name[20];//姓名
    char sex;//性别
    int age;//年龄
    int num;//学号
};
 
 
int main()
{
    struct Student s = { "zhangsan",'w',20,111 };
	return 0;
}

<3>匿名结构体定义


struct 
{
    char name[20];//姓名
    char sex[20];//性别
    int age;//年龄
} s = { "zhangsan","nan",20};

注意:结构体初始化与数组相同,都必须整体进行赋值。

结构体的自引用


struct node //初始话链表
{
	int a;
	struct Node next;
};

结构体的自引用就是结构体再套用自己

学过数据结构的朋友应该知道这是初始化链表

不过这一个代码有问题的

问题在于无法求出这个结构体的大小,不清楚这个结构体有多大,因为无法求出自引用的结构体有多大

所有自引用的结构体要用指针来访问


struct Node //初始话链表
{
	int a;
	struct Node* next;
};

故就可以通过指针来访问每一个结点

结构体的访问

当结构体定义且变量初始化完成后,就可以通过操作符来访问变量中的成员

当然,这里给出了两个操作符

分别是  .操作符和 -> 操作符

当使用结构体变量时,就用点操作符,当访问结构体指针变量就用箭头操作符

(1)通过结构体变量进行访问:


printf("%s\n",s.name);

(2)通过结构体指针进行访问:


printf("%s\n",ps->name);

结构体的传参

函数的调用有时候需要传一些参数

参数的类型可以是不同的类型,可以是数组,也可以是指针

同样结构体的传参也可通过传结构体或者传指针

传结构体


#include<stdio.h>  
struct tag
{
	int a;
	char b[20];
}s1 = { 100,"abcdef" };
void print()
{
	printf("%d", s1.a);
}
int main()
{
	print(s1);
	return 0;
}

传地址


#include<stdio.h>
struct tag
{
	int a;
	char b[20];
}s2 = { 100,"abcdef" };
void print(struct tag*s2)
{
	printf("%d", s2->a);
}
int main()
{
	print(&s2);
	return 0;
}

我们要知道函数传参是形参就是实参的临时拷贝

参数是要压栈的(向系统申请空间),既然是临时拷贝,就会再次再栈上开辟空间,当实参足够大时,显然会浪费一定的空间和时间

相比较与传结构体,传指针会更好 

结构体的内存对齐(强烈建议观看)

在另外一篇文章详细讲过——C语言结构体中内存对齐的问题理解

位段

可能有人没有听过什么是位段

位段的结构类型跟结构体有些类似可以类似结构体去学习

也可以说

位段是结构体特殊的实现

位段的声明

相较于结构体,位段的声明有两点不同

<1>规定位段的成员的必须是int,unsigned int ,signed int (但是写成char类型也没什么大的问题)

<2>位段的成员后面有一个冒号和一个数字


struct A  //位段的声明
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

位段的内存管理


#include<stdio.h>
struct A
{
	int a : 2;
	int b : 5;
	int c : 10;
	int d : 30;
};
int main()
{
	
	printf("大小是%d字节", sizeof(struct A));
	return 0;
}

为什么位段的大小是八个字节呢?

成员内包含的数字代表的是这个成员需要利用的内存,单位是bit。

位段成员申请内存时都是以四个字节或者一个字节单位(当成员是char类型时)

int a : 2; //申请4个字节,也就是32个bit位,利用两个还剩30个
int b : 5; //利用5个,还剩25个
int c : 10; //利用10个,还剩15个
int d : 30; //这里的十五不够,所以再申请了4个字节

最终的结果就是八字节

但问题是,变量d利用的空间是留下的15个bit加上重新申请的空间呢

这个结果在不同的环境的结果是不同的,所以位段的跨平台性比较差

位段使用的前提是你知道存储的内存大概有多大

就比如说年龄

十个bit位0111111111,最大值就可以达到1023

就不需要再申请一次利用一个int类型的空间大小

这就达到了节省内存的作用,存在即合理

位段的应用 


struct A
{
	char a : 3;
	char b : 4;
	char c : 5;
};
main()
{
	struct A s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	return 0;
}

位段的跨平台性

1.int位段被当成有符号数还是无符号数是不确定的,有时候系统会自动转化为无符号整形。

2.位段中最大位的数目不能确定。(因为在早期的16位机器int最大16,而32位机器int最大32)

3.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

意思当内存一个字节00000000,存入01010,可能会出现00001010或者01010000

4.当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是 舍弃剩余的位还是利用,这是不确定的。

 枚举类型

枚举类型适用于可以一一列举的类型

比如说星期、性别

枚举类型的定义


enum Day   //星期
{
	//枚举的可能取值
	Mon,
	Tues,
	Wed,
	Thir,
	Fri,
	Sta,
	Sun
};

enum Sex  //性别
{
	MALE,//0
	FEMALE,//1
	SECRET//2
};

枚举类型是有初始值的

如果你没赋予它初始值,就会默认从零开始,依次加一

枚举类型赋予初始值


#include<stdio.h>
enum Sex  //性别
{
	MALE = 4,
	FEMALE=10,
	SECRET//
};
main()
{
	printf("%d %d %d", MALE,FEMALE,SECRET);
	return 0;
}

可以看到,其实默认的值是可以改的

当某个成员被赋予某个值的时候,后续的成员就在此基础上加一

枚举类型的优点

1.相较于数字,枚举增加代码的可读性和可维护性

2.和#define定义的标识符比较枚举有类型检查,更加严谨。

3.防止了命名污染(封装)

4.便于调试

5.使用方便,一次可以定义多个常量

联合体类型

联合体类型也叫共用体

联合体的定义


uNIOn Un  
{
	int a;
	char b;
};

union是联合体关键字,Un是联合体的标签

联合体的特点

共用体,顾名思义,这里的共用就是公用内存

内存的也可被折叠


#include<stdio.h>
union Un
{
	char c;
	int i;
};
int main()
{
	union Un u = {0};
	printf("%d\n", sizeof(u));
	printf("%p\n", &u);
	printf("%p\n", &(u.c));
	printf("%p\n", &(u.i));
	return 0;
}

他们有相同的地址

c和i存放在同一块内存空间上,修改c或者i都会影响到另一个成员。

 联合体内存大小的计算

<1>联合体内存大小是最大成员的大小

<2>最大成员的大小如果不是最大对齐数的整数倍,就会对齐到最大对齐数的整数倍

(联合体也存在内存对齐)


#include<stdio.h>
union Un1
{
	char c[5];  
	int i;
};          
//Un1成员最大成员大小5,最大对齐数是4,所以Un1的大小是8;
union Un2
{
	char c[7];
		int i;
};
//Un2成员最大成员大小7,最大对齐数是4,所以Un2的大小是8;
int main()
{
	printf("%d\n", sizeof(union Un1));
	printf("%d\n", sizeof(union Un2));
	return 0;
}

到此这篇关于C语言自定义类型全解析的文章就介绍到这了,更多相关C语言 自定义类型内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C语言自定义类型全解析

本文链接: https://www.lsjlt.com/news/138732.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言自定义类型全解析
    目录前言结构体类型结构体的声明结构体变量的定义与初始化结构体的自引用结构体的访问结构体的传参传结构体传地址结构体的内存对齐(强烈建议观看)位段位段的声明位段的内存管理位段的跨平台性 ...
    99+
    2022-11-13
  • C语言:自定义类型详解
    目录一、结构体1.结构体变量的定义及初始化2.结构体内存对齐3.为什么要内存对齐呢?二、位段1.什么是位段2.位段的内存分配三、枚举1.枚举的定义2.枚举的优点四、联合(共用体)1....
    99+
    2022-11-12
  • C语言自定义类型全面系统理解
    目录一、结构体1.结构体的声明局部结构体变量全局结构体变量2.特殊声明3.结构体的自引用4.结构体变量的初始化5.结构体内存对齐 6.修改默认对齐数7.结构体传参传址调用原因:二、位...
    99+
    2022-11-13
  • C语言中自定义类型详解
    目录结构大小offsetof结构体对齐规则存在原因总结结构大小 我们先随便给出一个结构体,为了计算他的大小,我给出完整的打印方案: typedef struct num { cha...
    99+
    2022-11-13
  • 最新C语言自定义类型详解
    目录前言结构体结构体的基础知识结构和数组的区别结构体的声明结构体的特殊声明 结构体的自引用我们能不能结构体套结构体呢?那么怎么实现结构体自引用呢?结构体变量的定义和初始化我...
    99+
    2023-01-13
    C语言 自定义类型 C自定义类型详解
  • 怎么在C语言中自定义类型
    本篇文章为大家展示了怎么在C语言中自定义类型,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、初始结构体结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。下面举一个例子:s...
    99+
    2023-06-08
  • C语言编程C++自定义个性化类型
    目录自定义类型结构体声明一个结构体类型特殊声明结构体自引用结构体变量的定义和初始化结构体内存对齐结构体传参位段枚举联合(共用体)联合类型的定义联合类型的声明联合的特点判断当前机器的大...
    99+
    2022-11-12
  • C语言中的自定义类型是什么
    C语言中的自定义类型是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。结构大小我们先随便给出一个结构体,为了计算他的大小,我给出完整的打印方案:typedef st...
    99+
    2023-06-28
  • c语言如何自定义结构体类型
    在C语言中,可以使用`typedef`关键字来自定义结构体类型。`typedef`关键字用于为已存在的类型定义一个新的名称。以下是定...
    99+
    2023-09-04
    c语言
  • c语言string类型如何定义
    在C语言中,可以使用字符数组来表示字符串,并通过数组的最后一个元素设置为'\0'来表示字符串的结束。可以使用以下两种方式定义字符串:...
    99+
    2023-10-28
    c语言
  • C语言深入了解自定义数据类型的使用
    目录一、自定义数据类型(上)二、自定义数据类型(中)​​​​​三、自定义数据类型(下)​​​​​一、自定义数据类型(上) 类型命名关键字 (typedef) C语言中可以对类型赋予新...
    99+
    2022-11-13
  • C语言枚举类型如何定义
    C语言枚举类型可以使用关键字`enum`来定义。定义枚举类型的语法格式如下:```cenum 枚举类型名 {枚举常量1,枚举常量2,...
    99+
    2023-10-10
    C语言
  • c语言中byte类型如何定义
    在C语言中,没有直接定义byte类型的关键字,但可以使用unsigned char类型来表示一个字节大小的数据。具体定义方式如下: ...
    99+
    2023-10-24
    c语言
  • C语言常量类型怎么定义
    这篇文章主要介绍“C语言常量类型怎么定义”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C语言常量类型怎么定义”文章能帮助大家解决问题。常量的定义常量就是一个不变的量(比如圆周率,性别,身份证号码)C...
    99+
    2023-06-29
  • Go语言中类型别名和自定义类型的示例分析
    这篇文章主要介绍Go语言中类型别名和自定义类型的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Go语言中没有类的概念,也不支持“类”的继承等面向对象的概念。Go语言中通过结构...
    99+
    2022-10-19
  • Go语言中的自定义类型你了解吗
    目录1. 什么是自定义类型2. 如何定义自定义类型3. 自定义类型的方法4. 自定义类型的嵌入和组合5. 自定义类型的值接收者和指针接收者6. 自定义类型的类型方法7. 总结注:本篇...
    99+
    2023-05-18
    Go自定义类型使用 Go自定义类型原理 Go自定义类型
  • C语言自定义数据类型的结构体、枚举和联合详解
    结构体基础知识 首先结构体的出现是因为我们使用C语言的基本类型无法满足我们的需求,比如我们要描述一本书,就需要书名,作者,价格,出版社等等一系列的属性,无疑C语言的基本数据类型无法解...
    99+
    2022-11-12
  • C语言自定义类型详解(结构体、枚举、联合体和位段)
    目录前言一、结构体1、结构体类型的声明2、结构体的自引用3、结构体变量的定义和初始化4、结构体内存对齐5、结构体传参二、位段1、位段的定义 2、位段的内存分配3、位段的应用...
    99+
    2022-11-12
  • C语言关于自定义数据类型之枚举和联合体详解
    目录前言枚举枚举类型的定义枚举类型的优点枚举类型的使用枚举中需要注意的点联合体联合体类型的定义联合体的特点联合体的使用联合体存在内存对齐结语前言 在C语言的自定义数据类型中,除了我们...
    99+
    2022-11-12
  • C#如何自定义泛型类
    这篇文章主要为大家展示了“C#如何自定义泛型类”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C#如何自定义泛型类”这篇文章吧。Generic是Framework 2.0的新元素,中文名字称之为“...
    99+
    2023-06-18
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作