【C语言】自定义数据类型

建议学完指针再学

为什么要有自定义数据类型?

基本数据类型不能满足我们在编程中的要求时,需要自己定义一些数据类型使用。

结构体

如果我们想存储单个数据,可以直接用数组存储;那么如果我们想存储多个数据呢?

比如我们要存储学生的学号、姓名、性别、年龄,又该如何操作呢?这就要用到结构体了

结构体的定义

struct 结构体名
{成员列表
};

在定义结构体时,常常会用typedef起一个别名

【C语言】typedef

实例:

#include <stdio.h>
//定义结构体Student
struct Student{char s_id[10];char s_name[20];char s_sex[8];int s_age;
}; 
/*typedef起别名
typedef struct Student{char s_id[10];char s_name[20];char s_sex[8];int s_age;
}ST; 
定义变量时直接使用ST即可
ST stu;
*/
int main ()
{//结构体变量的初始化struct Student stu={"2408210","liuwen","male",18};//结构体成员访问:使用'.'访问printf("%s\t%s\t%s\t%d",stu.s_id,stu.s_name,stu.s_sex,stu.s_age);return 0;
}

在C语言中不存在结构体类型的强制转换

结构体指针变量

struct Student{char* s_id;char* s_name;char* s_sex;int* s_age;
};

结构体嵌套

#include <stdio.h>
struct Date{int year;int month;int day;
};
struct Student{char s_name[20];struct Date birthday;float score;
}; 
/*也可以直接这样写
struct Student{char s_name[20];struct Date{int year;int month;int day;}birthday;float score;
};
*/
int main ()
{struct Student stu={"liuwen",2000,10,1,99.5};printf("%s\t%d.%d.%d\t%.1f",stu.s_name,stu.birthday.year,stu.birthday.month,stu.birthday.day,stu.score);return 0;
}

结构体变量和指针

结构体类型指针访问成员的获取和赋值形式:

  1. (*p).成员名
  2. p->成员名

实例:

#include <stdio.h>
struct Inventory{//商品 char description[20];//货物名int quantity;//库存数据 
};
int main ()
{struct Inventory sta={"iphone",20};struct Inventory* stp=&sta;printf("%s %d\n",stp->description,stp->quantity);printf("%s %d\n",(*stp).description,(*stp).quantity);return 0;
}

结构体和函数

#include <stdio.h>
struct School{char s_name[20];int s_age;
};
void Print_a(struct School sx){printf("%s %d\n",sx.s_name,sx.s_age);
}
void Print_b(struct School* sp){printf("%s %d\n",sp->s_name,sp->s_age);
}
int main(){struct School sc={"xi'an",100};Print_a(sc);Print_b(&sc);return 0;
}

结构体和数组

结构体数组,是指数组中的每一个元素都是一个结构体类型。在实际应用中,C语言结构体数组常被用来表示有相同的数据结构的群体,比如一个班的学生,一个公司的员工等

#include <stdio.h>
struct Student{char s_name[20];int age;float score;
};
int main(){struct Student cla[]={{"李华",18,149.5},{"李雷",16,130},{"韩梅梅",16,141.5},};for(int i=0;i<3;i++){printf("%s\t%d\t%f\n",cla[i].s_name,cla[i].age,cla[i].score);}return 0;
}

计算结构体大小

#include <stdio.h>
struct node{char cha;char chb;int ia;
};
int main(){struct node sd={'a','b',2};printf("%d",sizeof(struct node));return 0;
}

输出结果为:8

让我们调整一下结构体成员的顺序:

struct node{char cha;int ia;char chb;
};

输出结果为:12

这是怎么一回事呢?为什么大小不是1+1+4=6呢?

原来是内存对齐惹的祸

【C语言】变量占用内存的大小&&内存对齐

共用体

成员共享同一块存储空间

共用体的定义

union 共用体名
{成员列表
};

定义和用法类比于结构体

共用体内存分配符合两项原则:

  1. 共用体的内存必须大于或等于其他成员变量中最大数据类型(包括基本数据类型和数组)的大小
  2. 共用体的内存必须是最宽基本数据类型的整数倍,如果不是,则填充字节

例1.成员变量都是基本数据类型的共用体

union data{int m;float x;char c;
}a;

共用体a的内存大小是最大数据类型所占的字节数,即int和float的大小,所以a的内存大小为4字节

例2.成员变量包含数组类型的共用体

union{int m;float x;char c;char str[5];
}b;

共用体b的最大数据类型为字符数组,但它的大小是5字节,不满足原则2.必须是最大基本数据类型的整数倍,所以填充3字节,共8字节

共用体变量的初始化和引用

在共用体变量的定义的同时,只能对其中一个成员的类型值进行初始化,这与它的内存分配也是响应的。

共用体变量初始化的格式如下:

union 共用体类型  共用体变量={其中一个成员的类型值};//必须用大括号括起来

完成共用体变量的初始化后,就可以引用共用体中的成员,共用体变量的引用与结构体类似,有直接引用和间接引用两种。

实例演示:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>struct Person
{char name[20];char role[20];union{char classroom[20];char office[20];}dept;
}person[3];int main() {for (int i = 0; i < 3; i++) {printf("please input your information:NO.%d\n", i + 1);printf("Name:");scanf("%s", &person[i].name);getchar();printf("Role:");scanf("%s", &person[i].role);getchar();if (strcmp(person[i].role, "student")==0) {printf("Classroom:");getchar();scanf("%s", &person[i].dept.classroom);}else if (strcmp(person[i].role, "teacher") == 0) {printf("Office:");	getchar();scanf("%s", &person[i].dept.office);}getchar();}for (int i = 0; i < 3; i++) {printf("please input your information:NO.%3d\n", i + 1);printf("\tName:%6s",person[i].name);printf("\tRole:%10s",person[i].role);if (strcmp(person[i].role, "student") == 0) {printf("\tClassroom:%s",person[i].dept.classroom);}else if (strcmp(person[i].role, "teacher") == 0) {printf("\tOffice:%6s",person[i].dept.office);}printf("\n");}
}

枚举类型

在程序中,可能需要为某些整数定义一个别名,我们可以利用预处理指令#define来完成这项工作,您的代码可能是:

#define MON 1
#define TUE  2
#define WED 3
#define THU  4
#define FRI  5
#define SAT  6
#define SUN  7

在此,我们定义一种新的数据类型,希望它能完成同样的工作。这种新的数据类型叫枚举型。

枚举类型的定义

格式:

enum 枚举类型名
{成员列表
};

示例:

enum  DAY
{MON = 1 , TUE, WED, THU, FRI, SAT, SUN
};
  1. 枚举型是一个集合,集合中的元素(枚举成员)是一些命名的整型常量,元素之间用逗号,隔开。
  2. DAY是一个标识符,可以看成这个集合的名字,是一个可选项,即是可有可无的项。
  3. 第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。
  4. 可以人为设定枚举成员的值,从而自定义某个范围内的整数。
  5. 枚举型是预处理指令#define的替代。
  6. 类型定义以分号**;**结束。

使用枚举类型对变量进行声明

方法一:枚举类型的定义和变量的声明分开

enum DAY
{MON = 1 , TUE, WED, THU, FRI, SAT, SUN
};
enum DAY yesterday;
enum DAY today;
enum DAY tomorrow; // 变量tomorrow的类型为枚举型enum DAY
enum DAY good_day, bad_day; // 变量good_day和bad_day的类型均为枚举型enum DAY

方法二:类型定义与变量声明同时进行:

enum  //跟第一个定义不同的是,此处的 标号DAY省略,这是允许的。
{saturday,sunday = 0 ,monday,tuesday,wednesday,thursday,friday
} workday; // 变量workday的类型为枚举型enum DAY
enum week { Mon = 1 , Tue, Wed, Thu, Fri Sat, Sun} days; // 变量days的类型为枚举型enum week
enum BOOLEAN { false , true } end_flag, match_flag; // 定义枚举类型并声明了两个枚举型变量

方法三:用typedef关键字将枚举类型定义成别名,并利用该别名进行变量声明:

typedef enum workday//enum workday中的workday可以省略
{saturday,sunday =  0 ,monday,tuesday,wednesday,thursday,friday
} workday; // 此处的workday为枚举型enum workday的别名
workday today, tomorrow; // 变量today和tomorrow的类型为枚举型workday,也即enum workday

注意:同一个程序中不能定义同名的枚举类型,不同的枚举类型中也不能存在同名的命名常量。错误示例如下所示:

错误声明一:存在同名的枚举类型

typedef enum
{wednesday,thursday,friday
} workday;typedef enum WEEK
{saturday,sunday =  0 ,monday,
} workday;

错误声明二:存在同名的枚举成员

typedef enum
{wednesday,thursday,friday
} workday_1;typedef enum WEEK
{wednesday,sunday =  0 ,monday,
} workday_2;

对枚举型的变量赋整数值时,需要进行类型转换

#include<stdio.h>
enum  DAY { MON = 1 , TUE, WED, THU, FRI, SAT, SUN };
int main()
{enum  DAY yesterday, today, tomorrow;yesterday  =  TUE;today  =  ( enum  DAY) (yesterday  +   1 );  // 类型转换tomorrow  =  ( enum  DAY)  30 ;  // 类型转换// tomorrow = 30;  // 错误printf( " %d %d %d \n " , yesterday, today, tomorrow);  // 输出:2 3 30
}

使用枚举型变量

#include<stdio.h>
enum
{ BELL       =   '\a' ,BACKSPACE  =   '\b' ,HTAB       =   '\t' ,RETURN     =   '\r' ,NEWLINE    =   '\n' , VTAB       =   '\v' ,SPACE      =   ' '
};
enum  BOOLEAN { FALSE = 0 , TRUE } match_flag;
int main()
{int  index = 0 ;int  count_of_letter= 0 ;int  count_of_space = 0 ;char str[] = "I'm Ely efod" ;match_flag  =  FALSE;for (; str[index]  != '\0' ; index ++ )if ( SPACE  !=  str[index] )count_of_letter ++ ;else{match_flag  =  ( enum  BOOLEAN)  1 ;count_of_space ++ ;}printf( "%s %d times %c" , match_flag  ?   "match"  :  "not match" , count_of_space, NEWLINE);printf( "count of letters: %d %c%c " , count_of_letter, NEWLINE, RETURN);
}

运行结果:

match 2 times
count of letters: 10

枚举类型与sizeof运算符

#include<stdio.h>
enum escapes
{ BELL       =   '\a' ,BACKSPACE  =   '\b' ,HTAB       =   '\t' ,RETURN     =   '\r' ,NEWLINE    =   '\n' , VTAB       =   '\v' ,SPACE      =   ' '
};
enum  BOOLEAN { FALSE = 0 , TRUE } match_flag;
int main()
{printf( "%d bytes \n" ,  sizeof (enum escapes));  // 4 bytesprintf( "%d bytes \n" ,  sizeof (escapes));  // 4 bytesprintf( "%d bytes \n" ,  sizeof (enum  BOOLEAN));  // 4 bytesprintf( "%d bytes \n" ,  sizeof (BOOLEAN));  // 4 bytesprintf( "%d bytes \n" ,  sizeof (match_flag));  // 4 bytesprintf( "%d bytes \n" ,  sizeof (SPACE));  // 4 bytesprintf( "%d bytes \n" ,  sizeof (NEWLINE));  // 4 bytesprintf( "%d bytes \n" ,  sizeof (FALSE));  // 4 bytesprintf( "%d bytes \n" ,  sizeof ( 0 ));  // 4 bytes
}

参考博文:

https://blog.csdn.net/weixin_48560325/article/details/124280883

https://blog.csdn.net/Jacky_Feng/article/details/109219560

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/5461.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

74、堆-数组中的第K个最大元素

思路&#xff1a; 直接排序是可以的&#xff0c;但是时间复杂度不符合。可以使用优先队列&#xff0c;代码如下&#xff1a; class Solution {public int findKthLargest(int[] nums, int k) {if (numsnull||nums.length0||k<0||k>nums.length){return Integer.MAX_VAL…

CST电磁仿真局部网格设置与仿真结构不参与仿真设置【基础教程】

局部网格设置 使用Local Mesh功能在特定结构&#xff08;区域&#xff09;设置网格 Simulation > Mesh > Local Mesh Properties 仿真模型的构成部件尺寸和复杂度是非常多样的&#xff0c;如果以最复杂的部分为准来划分网格不复杂的部分也会生成非常稠密的网格&#x…

如何判断嵌入式平台OpenCV在使用硬件编解码器?

01 涉及OpenCV编解码库的一个命令行工具 python3 -c import cv2; print(cv2.getBuildInformation()) 它可以打印输出详细的OpenCV编译参数和当前的媒体库相关参数&#xff0c;我的rk3588打印的信息是这样的&#xff1a; catlubancat:~$ python3 -c import cv2; print(cv2.getBu…

全面解析Unity至Unreal的项目迁移流程

引言 在游戏开发领域&#xff0c;Unity和Unreal Engine都是顶尖的选择&#xff0c;各自带有独特的优势。对于追求更高图形质量和更强大物理模拟的开发团队而言&#xff0c;将项目从Unity迁移到Unreal可能是一个值得考虑的选择。本文将详细介绍整个迁移流程&#xff0c;帮助开发…

[Java、Android面试]_24_Compose为什么绘制要比XML快?(高频问答)

欢迎查看合集&#xff1a; Java、Android面试高频系列文章合集 本人今年参加了很多面试&#xff0c;也有幸拿到了一些大厂的offer&#xff0c;整理了众多面试资料&#xff0c;后续还会分享众多面试资料。 整理成了面试系列&#xff0c;由于时间有限&#xff0c;每天整理一点&am…

Linux操作系统·进程管理

一、什么是进程 1.作业和进程的概念 Linux是一个多用户多任务的操作系统。多用户是指多个用户可以在同一时间使用计算机系统&#xff1b;多任务是指Linux可以同时执行几个任务&#xff0c;它可以在还未执行完一个任务时又执行另一项任务。为了完成这些任务&#xff0c;系统上…

数据库锁介绍

目录 1.数据库锁 事务的隔离级别 读未提交&#xff08;Read Uncommitted&#xff09; 读已提交&#xff08;Read Committed&#xff09; 可重复读&#xff08;Repeatable Read&#xff09; 串行化&#xff08;Serializable&#xff09; 幻读和不可重复读区别 2.Mysql中有…

Android binder死亡通知机制

在Andorid 的binder系统中&#xff0c;当Bn端由于种种原因死亡时&#xff0c;需要通知Bp端&#xff0c;Bp端感知Bn端死亡后&#xff0c;做相应的处理。 使用 Bp需要先注册一个死亡通知&#xff0c;当Bn端死亡时&#xff0c;回调到Bp端。 1&#xff0c;java代码注册死亡通知 …

【webrtc】MessageHandler 9: 基于线程的消息处理:执行Port销毁自己

Port::Port 构造的时候,就触发了一个异步操作,但是这个操作是要在 thread 里执行的,因此要通过post 消息 MSG_DESTROY_IF_DEAD 到thread跑:port的创建并米有要求在thread中 但是port的析构却在thread里 这是为啥呢?

豆瓣9.7,这部Java神作第3版重磅上市!

Java 程序员们开年就有重磅好消息&#xff0c;《Effective Java 中文版&#xff08;原书第 3 版&#xff09;》要上市啦&#xff01; 该书的第1版出版于 2001 年&#xff0c;当时就在业界流传开来&#xff0c;受到广泛赞誉。时至今日&#xff0c;已热销近20年&#xff0c;本书第…

自然语言处理(NLP)简介

自然语言处理&#xff08;NLP&#xff09;技术是一种使用计算机处理和理解自然语言的技术。以下是一些NLP技术的例子&#xff1a; 机器翻译&#xff1a;NLP可以用于自动翻译一种语言到另一种语言。例如&#xff0c;Google Translate使用NLP技术来将文本从一种语言翻译成另一种语…

三维SDMTSP:GWO灰狼优化算法求解三维单仓库多旅行商问题,可以更改数据集和起点(MATLAB代码)

一、单仓库多旅行商问题 多旅行商问题&#xff08;Multiple Traveling Salesman Problem, MTSP&#xff09;是著名的旅行商问题&#xff08;Traveling Salesman Problem, TSP&#xff09;的延伸&#xff0c;多旅行商问题定义为&#xff1a;给定一个&#x1d45b;座城市的城市集…

CST Studio初级教程 五

本课程将实例讲解CST 3D建模。CST 3D 建模有三个途径&#xff1a;一种方法是用Brick、Sphere、Cone、Torus、Cylinder、Bond Wire指令绘制实体。第二种方法是用Extrude Face、Rotate Face、loft在已有模型基础上生成实体。第三种方法是&#xff0c;先用2D绘图指令绘制Curves&am…

Cross-Origin Read Blocking (CORB)

Cross-Origin Read Blocking (CORB) 是一种安全机制&#xff0c;用于保护Web应用免受跨域读取攻击。 跨域读取攻击可能会导致网站上的敏感信息被恶意代码访问和读取。这种攻击方式通常利用浏览器对不同源的资源访问的限制进行绕过。 CORB通过在浏览器中引入一种新的安全检测机…

Apache POI 在java中处理excel

介绍: Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是&#xff0c;我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。 一般情况下&#xff0c;POI 都是用于操作 Excel 文件。 如何使用: 1.maven坐标引入 <depend…

Aker(安碁科技)晶振产品应用和选型

一、石英晶体振荡器简介 在电子电路系统中&#xff0c;特定的动作需要严格按照一定的顺序进行&#xff0c;以确保数据被正确处理和操作&#xff0c;时钟信号就成了系统工作的重要引导者。而且在多模块复杂电路系统中&#xff0c;为了确保不同功能模块能协调一致地工作&#xf…

【unity】(1)场景

Unity的场景&#xff08;Scene&#xff09;是构建游戏中各种环境和级别的基础。一个场景可以包含游戏中的所有对象&#xff0c;如角色、道具、地形等。 创建和管理场景 创建新场景&#xff1a; 在Unity编辑器中&#xff0c;选择File > New Scene&#xff0c;或者使用快捷键…

你用过最好用的AI工具有哪些

一&#xff1a;介绍 随着科技的飞速发展&#xff0c;AI技术已经深入到我们生活的每一个角落&#xff0c;为我们提供了前所未有的便利和可能性。在众多AI工具中&#xff0c;有几种特别受到人们的喜爱&#xff0c;并且在各自的领域中产生了深远的影响。 1、AI绘画工具 改图鸭AI绘…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(七)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 14 节&#xff09; P14《13.ArkUI组件-自定义组件》 将可变部分封装成组件的成员变量&#xff1a; 1、首先给标题添加两个图标&am…

用Docker 创建并运行一个MySQL容器

可以在DockerHub官网上荡:mysql - Official Image | Docker Hub 指令是:docker pull mysql; 因为文件比较大可能时间比较长&#xff0c;我是跟着黑马的课走的 课程提供的有文件&#xff0c;我就用已有的资源了。 在tmp目录里放入mysql.tar包 然后cd进去 输入指令:docker lo…