C 语言枚举、typedef 与预处理详解 - 指南

C 语言枚举、typedef 与预处理详解 - 指南

枚举类型 建议:如果定义不相干的常量,使用宏定义(符号常量);如果需要定义一组相关联的常量,如月份0 ~ 11,星期1~6,方向0 ~ 3,使用枚举,进行统一管理。以后正式开发中switch的case后面访问的就是枚举中的常量。

枚举的作用就是将多个拥有关联关系的常量组合到一起,提高代码的可读性。

说明 枚举定义了一组常量,我们在开发中直接使用这些常量。

枚举类型也可以类似于结构体一样定义变量等操作。

枚举常量有默认值,从0开始依次+1;定义是可以指定默认值,个别没有赋值的可以根据赋值依次+1推导。

特点 定义了一组常量,类似定义了多个符号常量(宏定义)

提高了代码的可读性

语法 ①定义枚举类型名称后,就可以定义该类型的变量(先类型,后变量)

注意:枚举的类型是符号常量

enum 枚举类型名 变量列表;

②在定义枚举类型的同时,定义该枚举类型的变量(类型+变量)

enum 枚举类型名{枚举元素列表} 变量列表;

③直接定义枚举变量(变量)

enum {枚举元素列表} 变量列表;

案例

/*************************************************************************

> File Name:

> Author: doris

> Description:

> Created Time: 2025-08-04 09:53:38

************************************************************************/

#include

/*

定义一个枚举类型

枚举类型一般首字母大写,主要是和枚举元素区分

**/

void test1()

{

enum Week

{

//定义枚举元素,元素本质上就是常量,在编译期间会被替换为字面量,命名和符号常量一样为:大写+下划线

//多个枚举元素之间使用逗号分隔

//SUN,MON,TUE,WED,THU,FRI,SAT 值依次为:0 ~ 6

SUN = 10,MON,TUE,WED,THU,FRI,SAT //值依次为:10~16

};

//1.直接访问枚举元素,适合于switch

printf("%d,%d,%d\n",SUN,WED,SAT); //10,13,16

//2.定义枚举类型的变量,适合于函数传参

enum Week week;

//初始化

week = TUE;//不能随便赋值,赋值枚举中定义的元素

printf("%d\n",week);

//3.定义枚举类型变量的同时赋值

enum Week week1 = THU;

printf("%d\n",week1);

//3.定义多个枚举类型变量

enum THU

{

A,B,C

} x, y;

x = B;

y = C;

printf("x=%d,y=%d\n",x,y);

}

void test2()

{

enum CaiQuan

{

SHI_TOU,JIAN_DAO,BU

};

printf("请输入0~2之间的整数:\n 0-石头,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 lnog size_t;

使用:

/*************************************************************************

> File Name: demo01.c

> Author: doris

> Description:

> Created Time: 2025-08-04 10:59:36

************************************************************************/

#include

int main(int argc, char *argv[])

{

//定义一个结构体

struct Student

{

int id;

char *name;

char sex;

int age;

};

//类型重命名

typedef struct Student Stu;

Stu stu = {1,"张三",'w',21};

printf("%d,%s,%c,%d",stu.id,stu.name,stu.sex,stu.age);

Stu *p = &stu;

printf("%d,%s,%c,%d",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;

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

为了跨平台的兼容性,例如:

size_t:类型重名后的数据类型:typedef unsigned long size_t;unit_16:类型重命名后的数据类型。案例:

/*************************************************************************

> File Name: demo02.c

> Author: doris

> Description:

> Created Time: 2025-08-04 11:16:06

************************************************************************/

#include

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",{90,23,67}};

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表示一张牌,包含:

花色属性suit(0-3表示普通花色♥♠♦♣,4表示小王,5表示大王)点数属性rank(0-12对应3-A,2,-1表示大小王)2.2 主要功能初始化牌组:

创建包含54张牌的牌组(52张普通牌+2张王牌)普通牌按花色(♠,♥,♣,♦)和点数(3-2)排列洗牌功能:

使用随机数对牌组进行随机排序确保每次运行洗牌结果不同(基于时间种子)发牌功能:

将洗好的牌发给3个玩家每个玩家17张牌剩余3张作为底牌显示功能:

打印每个玩家的手牌打印底牌3. 数据结构suits[]: 存储4种花色符号的字符串数组ranks[]: 存储13个点数等级的字符串数组jokers[]: 存储大小王描述的字符串数组Card结构体: 表示单张牌的数据结构牌组数组: deck[54]玩家手牌数组: player1[17], player2[17], player3[17]底牌数组: bottomCards[3]4. 用户交互程序运行后自动完成以下流程:

初始化牌组洗牌发牌显示发牌结果(3个玩家的手牌和底牌)5. 输出格式普通牌显示格式:花色+点数(如"♠ 3")王牌显示格式:“小王"或"大王”玩家手牌按顺序显示,每张牌用空格分隔底牌同样格式显示6. 源码

/*************************************************************************

> File Name: 综合案例:斗地主

> Author: doris

> Description:

> Created Time: 2025-08-04 14:23:07

************************************************************************/

#include

#include

#include

#include

#include

#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; //花色下标(0 ~3:普通牌, 4:小王,5:大王)

int rank;// 点数下标(0~12:普通牌,-1:大小王)

}Card;

//初始化一副牌

void initDeck(Card *deck);

//洗牌(打乱牌序)

void shuffeDeck(Card *deck);

//发牌(3个玩家各自17张牌,最后3张作为底牌)

void deelCards(Card *deck,Card *player1,Card *player2,Card *player3,Card *bottomCards);

//打印牌,根据数组中提供的花色和点数下标,获取相应的

void printCard(Card card);

int main(int argc,char *argv[])

{

//创建一个数组,用来存放一副牌(54)

Card deck[LEN];

//创建三个数组,用来存放3个玩家

Card player1[17],player2[17], player3[17];

//创建一个数组,用来存放底牌

Card bottomCards[3];

//初始化牌

initDeck(deck);

//洗牌

shuffeDeck(deck);

//发牌

deelCards(deck,player1,player2,player3,bottomCards);

//打印玩家手牌和底牌

int i;

printf("玩家1的手牌:");

for(i = 0 ; i< 17; i++) printCard(player1[i]); printf("\n");

printf("玩家2的手牌:");

for (i = 0; i < 17; i++) printCard(player2[i]); printf("\n");

printf("玩家3的手牌:");

for (i = 0; i < 17; i++) printCard(player3[i]); printf("\n");

printf("底牌:");

for (i = 0; i < 3; i++) printCard(bottomCards[i]); printf("\n");

return 0;

}

/**

* @brief 初始化一副牌

*

* @param deck 一副牌

*/

void initDeck(Card *deck)

{

//定义一个下标(0~53)

int index = 0;

//初始化52张普通牌

for (int suit = 0;suit < 4;suit++)//

{

for (int rank = 0;rank < 13;rank++)

{

//记录每张牌花色和点数的下标

deck[index].suit = suit; // 花色下标

deck[index].rank = rank; // 点数下标

index++;

}

}

//初始化大小王

deck[index].suit = 4; // 小王

deck[index].rank = -1;

index++;

deck[index].suit = 5;

deck[index].rank = -1;

}

/**

* @brief 洗牌(打乱牌序)

*

* @param deck

*/

void shuffeDeck(Card *deck)

{

//设置随机种子

srand((unsigned)time(NULL));

//洗牌

//遍历当前的有序牌

for (int i = 0; i < LEN;i++)

{

//随机生成0~53之间的数,作为交换牌的下标

int j = rand() % LEN;

//交换当前遍历牌跟随机牌的位置

Card temp = deck[i];

deck[i] = deck[j];

deck[j] = temp;

}

}

/**

* @brief 发牌(3个玩家各自17张牌,最后3张作为底牌)

*

* @param deck

* @param player1

* @param player2

* @param player3

* @param bottomCards

*/

void deelCards(Card *deck,Card *player1,Card *player2,Card *player3,Card *bottomCards)

{

//动态下标

int index = 0;

//给玩家发牌

/**for(int i = 0;i < LEN;i++)

{

if(i % 3 == 0)

else if (i % 3 == 1)

else if (i % 3 == 2)

}**/

for(int i = 0;i < 17;i++)

{

player1[i] = deck[index++];

player2[i] = deck[index++];

player3[i] = deck[index++];

}

//最后三张作为底牌

for(int i = 0;i < 3;i++)

{

bottomCards[i] = deck[index++];

}

}

void printCard(Card card)

{

if(card.suit == 4 || card.suit == 5 )

{

// 大小王

printf("%s",jokers[card.suit - 4]);

}

else

{

// 普通牌

printf("%s %s",suits[card.suit], ranks[card.rank]);

}

}

预处理C语言的编译步骤预处理编译汇编链接

什么是预处理 预处理就是在源文件(.c文件)编译之前,所进行的一部分预备操作,这部分操是由预处理器(预处理程序)自动完成。当源文件在编译时,编译器会自动调用预处理程序来完成预处理执行的操作,预处理执行解析完成才能进入下一步的编译过程。

查看预处理结果:

gcc 源文件 -E -o 程序名

预处理功能宏定义不带参数的定义语法:

#define 宏名称 宏值(替换文本)

**预处理机制:**此时的预处理只做数据替换,不做类型检查

**注意:**宏定义不会占用内存空间,因为在编译前已经将宏名称替换成了宏值

**宏展开:**在预处理阶段将宏名称替换成宏值的过程称之为“宏展开”。

案例:

/*************************************************************************

> File Name: demo01.c

> Author: 千夕

> Description:

> Created Time: 2025年05月29日 星期四 10时12分50秒

************************************************************************/

#include

#define PI 3.1415926

int main(int argc,char *argv[])

{

float l,s,r,v;

printf("请输入圆的半径:\n");

scanf("%f",&r);

// 计算周长

l = 2.0 * PI * r;

// 计算面积

s = PI * r * r;

printf("l=%10.4f\ns=%10.4f\n",l,s);

return 0;

}

/*************************************************************************

> File Name: demo01.c

> Author: 千夕

> Description:

> Created Time: 2025年05月29日 星期四 10时12分50秒

************************************************************************/

#include

#define PI 3.1415926

int main(int argc,char *argv[])

{

float l,s,r,v;

printf("请输入圆的半径:\n");

scanf("%f",&r);

// 计算周长

l = 2.0 * PI * r;

// 计算面积

s = PI * r * r;

printf("l=%10.4f\ns=%10.4f\n",l,s);

return 0;

}

带参数的定义语法:

#define 宏名(参数列表) 替换表达式

面试题:

#define MULTI(a,b) (a)*(b)

#define MULTI(a,b) a * b

实现:

/*************************************************************************

> File Name: demo02.c

> Author: 千夕

> Description:

> Created Time: 2025年05月29日 星期四 10时22分23秒

************************************************************************/

#include

// 带参数的宏定义,宏名一般小写

#define MULTI_1(a,b) (a) * (b)

#define MULTI_2(a,b) a * b

int main(int argc,char *argv[])

{

int result1 = MULTI_1(7+2,3); // (7+2) * (3) = 27

printf("%d\n",result1);

int result2 = MULTI_2(7+2,3); // 7 + 2 * 3 = 13

printf("%d\n",result2);

return 0;

}

宏定义的作用域#define 命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到本源文件结束。

可以用#undef命令终止宏定义的作用域。

案例:

/*************************************************************************

> File Name: demo04.c

> Author: 千夕

> Description:

> Created Time: 2025-08-04 17:34:58

************************************************************************/

#include

#define PI 3.14 // PI的有效范围:10~18行

#define DAY 29

void func1()

{

float r = 4;

float s = PI * r * r; // 预处理后:float s = 3.14 * r * r

int day = DAY; // 预处理后:int day = 29;

}

#undef PI// 终止了 PI的范围

#define PI 3.1415926

void func2()

{

float r = 4;

float s = PI * r * r; // 预处理后:float s = 3.1415926 * r * r

int day = DAY; // 预处理后:int day = 29;

}

int main(int argc, char *argv[])

{

return 0;

}

在宏定义中引用已定义的宏名案例:

/*************************************************************************

> File Name: demo04.c

> Author: 千夕

> Description:

> Created Time: 2025年05月29日 星期四 10时38分29秒

************************************************************************/

#include

#define R 3.0 // 半径

#define PI 3.14

#define L 2 * PI * R // 周长 在宏定义的时候,引入已定义的宏名

#define S PI * R * R // 面积

#define P_WIDTH = 800

#define P_HEIGHT = 480

#define SIZE = P_WIDTH * P_HEIGHT

int main(int argc,char *argv[])

{

printf("L=%f\nS=%f\n",L,S);// 预处理后:2 * 3.14 * 3.0, 3.14 * 3.0 * 3.0

return 0;

}

相关推荐

一篇吃透深圳六大热门行业
365游戏中心正式版

一篇吃透深圳六大热门行业

📅 10-11 👁️ 2033
手機相機黑屏怎麼辦?解決手機相機問題的完整指南
bt365账户为什么封

手機相機黑屏怎麼辦?解決手機相機問題的完整指南

📅 11-28 👁️ 4500
小蓝单车怎么锁车 小蓝单车怎么还车
bt365账户为什么封

小蓝单车怎么锁车 小蓝单车怎么还车

📅 07-23 👁️ 9319
dnf月轮山刷哪个
bt365账户为什么封

dnf月轮山刷哪个

📅 11-04 👁️ 9501
女高中生 (日本)
365游戏中心正式版

女高中生 (日本)

📅 07-09 👁️ 4220
河传_何处,烟雨
365betapp

河传_何处,烟雨

📅 08-26 👁️ 3313