详细介绍:C 语言:第 20 天笔记:typedef(类型重命名规则、应用场景与实战案例)

news/2025/9/23 12:58:29/文章来源:https://www.cnblogs.com/lxjshuju/p/19106993

C语言:第20天笔记

内容提要

构造类型:枚举类型

使用建议

定义

  • 一般情况下,定义常量使用宏定义(#define 宏名称 宏值),宏定义适合无关联关系的常量;
  • 当需要对一组有关联关系的量(如月份011、星期06、方向0~3等)进行定义时,宏定义清晰度低、不便于统一管理且会增加代码量,此时需使用枚举;
  • 枚举的作用是将多个有关联关系的常量组合到一起,提高代码的可读性。

说明

  1. 枚举定义了一组常量,开发中可直接使用这些常量(常用);
  2. 枚举类型也可类似于结构体定义变量等操作(不常用);
  3. 枚举常量有默认值,从0开始依次+1;可在定义时指定默认值,若个别未赋值,可根据已赋值常量依次+1推导。

特点

  1. 定义了一组常量,类似于定义了多个符号常量(宏定义);
  2. 提高了代码的可读性。

语法

语法分类格式说明
先定义类型后定义变量enum 枚举类型名 变量列表;定义枚举类型名后,再定义该枚举类型的变量,枚举的元素是符号常量
定义类型同时定义变量enum 枚举类型名{枚举元素列表} 变量列表;在定义枚举类型的同时,定义该枚举类型的变量
直接定义枚举变量enum {枚举元素列表} 变量列表;不单独定义枚举类型名,直接定义枚举变量

案例(demo01.c)

#include <stdio.h>void test1(){// 定义一个枚举类型// 注意:枚举类型名一般首字母大写,主要是跟枚举元素名区分enum Week{// 定义枚举元素,元素本质上就是常量,在编译期,会被替换为字面量// 枚举元素的命名和符号常量命名一致,都是大写+下划线// 多个枚举元素之间使用逗号分隔// SUN,MON,TUE,WED,THU,FRI,SAT // 此时,这7个常量的值依次为:0~6SUN = 10, MON, TUE, WED, THU, FRI, SAT // 此时,这7个常量的值依次为:10~16};// 1. 直接访问枚举元素,适合于switchprintf("%d,%d,%d\n", SUN, WED, SAT);// 10,13,16// 2. 定义枚举类型的变量,适合于函数传参enum Week week;// 初始化week = TUE;// 不能随便赋值,赋值一定是这个枚举中定义的元素printf("%d\n", week);// 12// 3. 定义枚举类型变量的同时赋值enum Week week1 = THU;printf("%d\n", week1);// 14// 4. 可以定义多个枚举变量enum THU{A, B, C} x, y;// 赋值x = B;y = C;printf("x=%d,y=%d\n", x, y);// 1,2}void test2(){// 定义枚举类型enum CaiQuan{SHI_TOU, JIAN_DAO, BU};printf("请输入0~2之间的整数:\n0-石头,1-剪刀,2-布\n");int choice;scanf("%d", &choice);switch (choice) {case SHI_TOU:printf("石头\n");break;case JIAN_DAO:printf("剪刀\n");break;case BU:printf("布\n");break;}}int main(int argc, char *argv[]){test1();test2();return 0;}

typedef

说明

给类型重命名,不会影响到类型本身。

作用

给已有的类型起别名。

格式

typedef 已有类型名 重命后的类型名;
示例:typedef unsigned long size_t;

使用案例(demo02.c)

#include <stdio.h>int main(int argc, char *argv[]){// 方式1:先定义数据类型,再重命名// 定义一个结构体struct Student{int id;char *name;char sex;int age;};// 类型重命名typedef struct Student Stu;// 将 struct Student 重命名为Stu// 使用新类型名// 定义结构体实例Stu stu = {1,"张三",'w',21};printf("%d,%s,%c,%d\n", stu.id, stu.name, stu.sex, stu.age);Stu *p = &stu;printf("%d,%s,%c,%d\n", p->id, p->name, p->sex, p->age);// 方式2:定义数据类型的同时重命名typedef struct PersonInfo{int a;double b;} Per;// 定义变量Per per = {2, 4.5};printf("%d,%.2f\n", per.a, per.b);// 定义指针Per *p1 = &per;printf("%d,%.2f\n", p1->a, p1->b);return 0;}

应用场景

数据类型复杂(结构体、共用体、枚举、结构体指针、无符号的长整型)时使用。

跨平台兼容性案例

C语言标准提供:
typedef signed long int_int64_t;
typedef unsigned Long intuint64_t;

常见跨平台类型重命名:

  1. size_ttypedef unsigned long size_t;
  2. unit_16:类型重命名后的数据类型。

进阶案例(demo03.c)

#include <stdio.h>struct Student{int age;char *name;double scores[3];};typedef struct Student Stu_t;// 对类型重命名typedef Stu_t* pStu_t;// 结构体指针重命名void test1(){Stu_t s1 = {21, "zhangsan", {99, 98, 97}};printf("%d,%s,%.2lf,%.2lf,%.2lf\n", s1.age, s1.name, s1.scores[0], s1.scores[1], s1.scores[2]);Stu_t *p;p = &s1;printf("%d,%s,%.2lf,%.2lf,%.2lf\n", (*p).age, p->name, p->scores[0], p->scores[1], p->scores[2]);}int main(int argc, char *argv[]){test1();return 0;}

综合案例:斗地主

1. 程序概述

这是一个模拟斗地主游戏发牌过程的C语言程序,实现了扑克牌的初始化、洗牌和发牌功能。

2. 功能需求

2.1 扑克牌定义

使用结构体Card表示一张牌,包含:

2.2 主要功能
  1. 初始化牌组
    • 创建包含54张牌的牌组(52张普通牌+2张王牌);
    • 普通牌按花色(♠,♥,♣,♦)和点数(3-2)排列。
  2. 洗牌功能
    • 使用随机数对牌组进行随机排序;
    • 确保每次运行洗牌结果不同(基于时间种子)。
  3. 发牌功能
    • 将洗好的牌发给3个玩家;
    • 每个玩家17张牌;
    • 剩余3张作为底牌。
  4. 显示功能
    • 打印每个玩家的手牌;
    • 打印底牌。

3. 数据结构

4. 用户交互

程序运行后自动完成以下流程:

  1. 初始化牌组;
  2. 洗牌;
  3. 发牌;
  4. 显示发牌结果(3个玩家的手牌和底牌)。

5. 输出格式

6. 源码

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <math.h>#include <time.h>#define LEN 54// 定义扑克牌的花色和点数const char *suits[] = {"♣","♦","♥","♠"};const char *ranks[] ={"3","4","5","6","7","8","9","10","J","Q","K","A","2"};// 点数const char *jokers[] = {"小王","大王"};// 大小王typedef struct{int suit;// 牌花色int rank;// 底数} Card;/*** @brief 初始化扑克*/void initCards(Card *deck);/*** @brief 洗牌*/void shuffDeck(Card *deck);void dealCard(Card *deck, Card *bottomCards, Card players[3][17]);void printfCard(Card players[3][17]);int main(int argc, char *argv[]){// 创建一个数组,存放一副牌(54张包括大小王)Card deck[LEN];// 创建三个玩家Card players[3][17];// 创建一个数组用来存放底牌Card bottomCards[3];// 初始化牌initCards(deck);// 洗牌shuffDeck(deck);// 发牌dealCard(deck,bottomCards,players);// 展示牌printfCard(players);return 0;}/*** @brief 初始化扑克*/void initCards(Card *deck){int index = 0;for(int i = 0; i <4; i++){for(int j = 0;i <13; j++){deck[index].rank = j;deck[index].suit = i;index++;}}// 初始化大小王deck[index].suit = 4;// 小王deck[index].rank = -1;index++;deck[index].suit = 5;// 大王deck[index].rank = -1;}// 洗牌void shuffDeck(Card *deck){srand((unsigned)time(NULL));// 洗牌for (int i = 0; i < LEN; i++){int j = rand() % LEN;// 0-53Card temp = deck[i];deck[i] = deck[j];deck[j] = temp;}}void dealCard(Card *deck, Card *bottomCards, Card players[3][17]){int index = 0;for(int i = 0;i <17; i++){for(int j = 0;j <3; j++){players[j][i] = deck[index++];}}// 底牌for(int i=0;i<3; i++){bottomCards[i] = deck[index++];}}// 打印void printfCard(Card players[3][17]){for(int i = 0;i <3; i++){printf("第%d个玩家的牌是:",i+1);for(int j = 0; j <17; j++){Card card = players[i][j];if (card.suit == 4 || card.suit == 5){// 大小王printf("%s ",jokers[card.suit - 4]);}printf("%s %s ",suits[card.suit], ranks[card.rank]);}}}

运行结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

预处理

一、C语言的编译步骤

C语言程序从源代码到可执行文件,需经历以下4个核心步骤,预处理是整个流程的第一步:

  1. 预处理:由预处理器处理源文件中的预处理指令(如#define#include等),生成预处理文件(.i格式);
  2. 编译:编译器对预处理文件进行词法分析、语法分析、语义分析及优化,生成汇编代码文件(.s格式);
  3. 汇编:汇编器将汇编代码转换为机器可识别的二进制目标文件(.o.obj格式);
  4. 链接:链接器将多个目标文件与标准库(如libc)组合,生成最终可执行文件(如Windows下的.exe、Linux下的无后缀可执行文件)。

编译流程示意图

源文件(.c) → 预处理(cpp) → 预处理文件(.i) → 编译(cc1) → 汇编文件(.s) → 汇编(as) → 目标文件(.o) → 链接(ld) → 可执行文件

二、什么是预处理

预处理是在源文件(.c文件)编译之前,由预处理器自动完成的预备操作。当编译器对源文件进行编译时,会先调用预处理器执行预处理操作,只有预处理解析完成后,才能进入后续的编译过程。

查看预处理结果

通过gcc编译器的-E选项可查看预处理后的结果,命令格式如下:

gcc 源文件 -E -o 预处理输出文件名

例如,对demo01.c进行预处理并输出到demo01.i,命令为:gcc demo01.c -E -o demo01.i

三、预处理核心功能:宏定义

宏定义是预处理阶段最常用的功能之一,用于将一个标识符(宏名)定义为一个字符串(宏值),在预处理阶段会将代码中所有宏名替换为对应的宏值(即“宏展开”)。

1. 不带参数的宏定义

语法
#define 宏名称 宏值(替换文本)
  • 预处理机制:仅做文本替换,不进行类型检查;
  • 内存特性:宏定义不占用内存空间,因为编译前宏名已被替换为宏值;
  • 宏展开:预处理阶段将宏名替换为宏值的过程称为“宏展开”。
案例(demo01.c)
#include <stdio.h>#define PI 3.1415926 // 定义宏PI,宏值为3.1415926int main(int argc, char *argv[]){float l, s, r;printf("请输入圆的半径:\n");scanf("%f", &r);// 计算周长(宏PI会被替换为3.1415926)l = 2.0 * PI * r;// 计算面积(宏PI会被替换为3.1415926)s = PI * r * r;printf("l=%10.4f\ns=%10.4f\n", l, s);return 0;}
宏展开后的效果

预处理后,代码中PI会被直接替换为3.1415926,关键代码展开如下:

l = 2.0 * 3.1415926 * r;
s = 3.1415926 * r * r;

2. 带参数的宏定义

带参数的宏定义允许宏名接收参数,替换时会将宏体中的参数占位符替换为实际传入的参数,类似函数但无函数调用开销(仅文本替换)。

语法
#define 宏名(参数列表) 替换表达式
注意事项(面试高频考点)

带参数的宏定义需注意括号的使用,若缺少括号可能导致运算优先级错误。例如:

  • 错误写法:#define MULTI(a,b) a * b
    当调用MULTI(7+2, 3)时,展开为7+2*3,结果为13(不符合预期);
  • 正确写法:#define MULTI(a,b) (a) * (b)
    当调用MULTI(7+2, 3)时,展开为(7+2)*(3),结果为27(符合预期)。
案例(demo02.c)
#include <stdio.h>// 带参数的宏定义,宏名一般小写(区分函数名)#define MULTI_1(a,b) (a) * (b) // 正确:参数加括号#define MULTI_2(a,b) a * b // 错误:参数无括号int main(int argc, char *argv[]){// 调用MULTI_1:(7+2)*(3) = 27int result1 = MULTI_1(7+2, 3);printf("%d\n", result1);// 调用MULTI_2:7+2*3 = 13(结果不符合预期)int result2 = MULTI_2(7+2, 3);printf("%d\n", result2);return 0;}

3. 宏定义的作用域

  • 默认作用域#define命令需写在函数外部,宏名的有效范围从定义处开始,到本源文件结束;
  • 终止作用域:可通过#undef命令主动终止宏定义的作用域,后续代码中该宏名不再生效。
案例(demo04.c)
#include <stdio.h>#define PI 3.14 // PI的有效范围:从定义处(第8行)到#undef处(第18行)#define DAY 29 // DAY的有效范围:从定义处(第10行)到本源文件结束void func1(){float r = 4;float s = PI * r * r;// 预处理后:3.14 * r * r(PI有效)int day = DAY;// 预处理后:29(DAY有效)}#undef PI // 终止PI的作用域,后续代码中PI失效#define PI 3.1415926 // 重新定义PI,作用域从第20行到本源文件结束void func2(){float r = 4;float s = PI * r * r;// 预处理后:3.1415926 * r * r(新PI有效)int day = DAY;// 预处理后:29(DAY仍有效)}int main(int argc, char *argv[]){return 0;}

4. 宏定义的嵌套引用

宏定义支持嵌套,即一个宏的宏值中可以引用其他已定义的宏名,预处理时会逐层展开所有宏。

案例(demo04.c)
#include <stdio.h>#define R 3.0 // 定义宏R(半径)#define PI 3.14 // 定义宏PI(圆周率)#define L 2 * PI * R // 嵌套引用PI和R,计算周长#define S PI * R * R // 嵌套引用PI和R,计算面积// 错误示例:宏定义中不应加等号(会导致替换错误)#define P_WIDTH = 800 #define P_HEIGHT = 480#define SIZE = P_WIDTH * P_HEIGHTint main(int argc, char *argv[]){// 预处理后:L展开为2*3.14*3.0,S展开为3.14*3.0*3.0printf("L=%f\nS=%f\n", L, S);return 0;}

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

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

相关文章

中国建设银行的网站地产网站开发公司

以文章multi-label learning from single positive为例&#xff1b; 手动print打印出你不懂的地方&#xff1b;把不会的地方单独拎出来&#xff0c;重新创建一个小文件单独运行&#xff1b;问神奇的chatgpt&#xff0c;github上有个学术型chatgpt可以帮你读懂项目代码&#xf…

榆林做网站的公司电话遵义交通建设网站

神经网络的三个特征是层次结构、权重共享和非线性激活函数。 层次结构&#xff1a;神经网络由多个层组成&#xff0c;包括输入层、隐藏层和输出层。这种层次结构使得神经网络能够逐层提取数据的特征&#xff0c;并且通过调整每一层的权重来学习数据的表征。 权重共享&#xff…

中小企业商务网站建设如何建英文网站

dc3 windows 本地搭建步骤&#xff1a; ​​ 必要软件环境 进入原网页# 务必保证至少需要给 docker 分配&#xff1a;1 核 CPU 以及 4G 以上的运行内存&#xff01; JDK : 推荐使用 Oracle JDK 1.8 或者 OpenJDK8&#xff0c;理论来说其他版本也行&#xff1b; Maven : 推荐…

江西做网站的公司有哪些网站改标题

1、Struts2和SpringMVC的区别(1)设计理念&#xff1a;前者为有状态的Action(均为多例)&#xff0c;Action对象属性字段承载请求、响应&#xff0c;后者一般为无状态的Controller&#xff0c;请求直接封装到方法的参数中&#xff1b;(2)集中访问点不同&#xff1a;都属于前端控制…

郑州做网站公司有多少12380网站建设情况总结

一、环境准备 安装 JDK 1.7 二、下载 Nexus 压缩文件 下载地址&#xff1a;http://www.sonatype.org/nexus/archived/ 三、上传压缩文件 四、解压缩文件 五、配置环境变量 1、临时配置 mvn clean package -Dmaven.test.skiptrue -Dmaven.javadoc.skiptrue命令&#xff1a;expor…

购物网站开发项目意义企业融资贷款

数学规划 (最速下降法,c语言编程).doc数 学 规 划 课 程 设 计题目&#xff1a;用最速下降法求解无约束非线性规划问题姓名&#xff1a;学号&#xff1a;成绩&#xff1a;2011年6月用最速下降法求解无约束非线性规划问题摘要&#xff1a;无约束非线性规划问题是一类重要的数学规…

企业如何选择适合自身行业的ERP系统?

企业如何选择适合自身行业的ERP系统?在整理企业信息化选型资料时发现,不同行业因业务模式、管理重点和流程特点的差异,对ERP系统的需求存在显著区别。例如,离散制造企业关注生产排程与物料齐套,商贸流通类企业更重…

Rust 登堂 之 Sized和不定长类型 DST(七) - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Screaming Architecture:让架构自己说话

什么是 Screaming Architecture? "Screaming Architecture"(呐喊架构)是由著名软件架构师 Robert C. Martin(Uncle Bob)提出的一个概念。这个概念的核心思想是:一个好的软件架构应该能够清晰地表达出这…

BOE(京东方)携手UNESCO联合主办WCBR“科学十年”分会 彰显中国科技企业可持续发展实力

9月22日,第五届世界生物圈保护区大会(简称WCBR)在杭州隆重开幕,这不仅是世界生物圈保护区大会第一次在中国举办,也是首次在亚太地区举办。作为联合国教科文组织(UNESCO)“人与生物圈计划”体系内规模最大、覆盖…

使用Cyclops.PdfKit根据pdf模板生成pdf文件

一、技术准备环境配置依赖库安装:使用NuGet包管理器集成Cyclops.PdfKit组件(最低要求.NET 6 SDK) dotnet add package cyclops-pdfkit --version 2.3.1 注意:生产环境建议锁定版本号以避免兼容性问题模板预处理:…

不关闭网站 备案seo搜索引擎官网

一、实验目的 熟练运用Python运算符。熟练运用Python内置函数。掌握Python的基本输入输出方法。了解lambda表达式作为函数参数的用法。掌握列表、元组、字典、集合的概念和基本用法。了解Python函数式编程模式。 二、实验内容&#xff1a; 1. 在命令模式测试如下命令&#x…

帮人做彩票网站淘特app推广代理

因为苹果后台的调整&#xff0c;电脑端的自签工具 Cydia Impactor 一直无法使用&#xff0c;如今虽然没有等到大胡子对 Cydia Impactor 适配更新&#xff0c;却等到了全新的替代工具。先说下为什么 Cydia Impactor 为什么让那么多人惦记&#xff0c;虽然对于不越狱安装越狱工具…

陕西省建设集团公司网站网站标题与关键词

服务器能运行什么应用 服务器是一种应用范围很广的网络技术产品&#xff0c;它在影视、视频以及医疗和金融等多个领域&#xff0c;都可以发挥使用价值&#xff0c;那么服务器能运行什么应用?大家跟着壹基比小鑫一起来了解吧&#xff01; 服务器的作用是什么&#xff1f; 服…

微信公众号和微网站个人域名免费网站

光伏EPC项目管理系统是一种适用于工程项目的管理软件&#xff0c;它强调在整个项目周期中的综合性管理理念&#xff0c;涵盖了从规划、设计、采购、施工到交付等全过程&#xff0c;帮助用户实现高效的项目管理。 1.增强项目团队之间的协作与沟通&#xff1a;光伏EPC项目管理系统…

新网站如何才做被百度收录网站上线倒计时页面

在我们之前的基础篇中,我们已经初步了解了DSL的架构与基础结构。现在,我们将进一步学习DSL的查询语句,这些查询语句对于我们的工作和学习而言至关重要。 DSL(Domain Specific Language)是一种专门用于特定领域的编程语言。在Elasticsearch(ES)中,DSL被广泛用于构建灵活…

做网站怎么安装数据库网站建设属于什么专业

一&#xff1a;连接 1&#xff1a;本地连接 mysql -u用户名 -p密码 2&#xff1a;连接远程服务器 mysql -u用户名 -p密码 -hip地址 -P端口号 线下修改远程服务端上部署的mysql服务器 二&#xff1a;创建数据库 create database 名字 utf8; 三&#xff1a;显示数据库 show datab…

免费企业查询网站时代设计网 新网站

Lightbend最近对2000多个JVM开发人员进行了调查&#xff0c;结果刚刚发布。 开展该调查的目的是发现&#xff1a;发展趋势与IT基础设施趋势之间的相关性&#xff0c;处于数字化转型前沿的组织如何使他们的应用程序现代化以及当今对新兴开发人员技术最为关注的实际生产使用情况细…

二级制流量算法熵值计算,N-Gram 算法(二:改进) - 教程

二级制流量算法熵值计算,N-Gram 算法(二:改进) - 教程2025-09-23 12:41 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important…