C语言(十一)枚举;结构

11.1.1 枚举

常量符号化:用符号而不是具体的数字来表示程序中的数字。
让用户输入颜色的代号,我们输出对应的颜色:可以用const int 和switch来解决。

const int red=0;
const int yellow=1;
const int green=2;

int main()
{
	int color=-1;
	char *colorname=NULL;
	printf("请输入你喜欢的颜色的代码");
	scanf("%d",&color);
	switch(color){
	case red:colorname="red";break;
	case yellow:colorname="yellow";break;
	case green:colorname="green";break;
	default:colorname="unknown";break;
	}
	printf("%s",colorname);
	return 0;

再把这件事再往前推进一点,我们使用枚举而不是单独定义const int变量。

enum COLOR{RED,YELLOW,GREEN};
int main(){
	int color=-1;
	char *colorname=NULL;
	printf("输入你喜欢的颜色代码:");
	scanf("%d",&color);
	switch(color){
	case RED:colorname="red";break;//在case处就可以直接使用RED YELLOW和GREEN来取代0,1,2
	case YELLOW:colorname="yellow";break;
	case GREEN:colorname="green";break;
	default:colorname="unknown";break;
	}
	printf("你喜欢的颜色是%s\n",colorname);
	return 0;
}

枚举是一种用户定义的数据类型,使用以下格式定义:
enum 枚举类型名{名字0,名字1……名字n};enum是enumeration。
枚举类型名通常不用,我们用的是大括号中的名字,因为他们就是常量符号,类型一定是int,值从0到n。比如上例中,RED=0,YELLOW=1,GREEN=2。
当需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量值名字。
在函数中使用时要记得说上前缀enum

enum color {red,yellow,green};
void f(enum color c);
int main()
{
	enum color t= red;
	scanf("%d",&t);
	f(t);
	return 0;
}

void f(enum color c)
{
	printf("%d\n",c);
}

这样可以像int一样输入输出。
因为定义中的名字是从0到n按顺序排列的,这样要遍历时或者要建立数组时就会很方便。

enum COLOR{RED,YELLOW,GREEN,numcolors};//结尾的numcolors表示数组的结尾,同时也可以表示enum中元素的个数。
int main()
{
	int color=-1; 
	char *ColorNames[numcolors]={
		"red","yellow","green",
	};
	char *colorname=NULL;
	printf("请输入你喜欢的颜色的代码");
	scanf("%d",&color);
	if(color>=0&&color<numcolors) colorname=ColorNames[color];
	else colorname="unknown";
	printf("你喜欢的颜色是%s",colorname);
	return 0;
}

另外,声明枚举量的时候可以指定特殊值,不一定非要按顺序从0开始。
enum color{red=1,yellow,green=5};如果输出%d,green 就会输出5。
但是枚举只是int,即使给它赋不存在的值(比如上例中,我们enum color c=0;也没有关系)也不会有warning或error。
枚举虽然可以当做类型来使用,但是并不好用。现在通常定义一些排比的符号量,这样比const int一个个来方便。
枚举比后面会讲到的宏(marco)好,因为枚举有类型int。

11.2.1 结构类型

我们已经知道,在c中我们要表达的数据,要有变量,还要有类型。
如果要表达的数据比较复杂(比如日期,包括年、月、日;或时间,包括时、分、秒),而我们又希望用一个整体去表达,就要用到C语言的结构。
结构是一个复合的数据类型,在里面有很多各种类型的“成员”,然后可以用一个变量来表达多个数据。

int main()
{
	struct date{
		int day;
		int month;
		int year;
	};//声明时,结尾有个分号!!
	struct date today;//像枚举一样不要忘记开头,struct
	today.day=12;
	today.month=3;
	today.year=2021;
	printf("Today's date is %i-%i-%i.",today.year,today.month,today.day);
	return 0;
}

当然,和之前本地、全局变量一样,如果结构是在一个函数内部声明的,则该结构只能在该函数内部使用。在函数外声明就可以在多个函数内使用了。
另一种声明方式:

struct{
	int x;
	int y;
}p1,p2;

p1和p2都是一种无名结构,都包含x和y。没有声明结构名字,临时造了两个无名结构出来。
不过,最常见的还是要声明结构名字的形式。

struct point{
	int x;
	int y;
}p1,p2;

p1,p2都是point,都包含x和y。

monthdayyear
11232007
today的内存中包含month, day, year.
还有一件要注意的事就是 声明结构类型定义结构变量 要区分。声明类型后方可定义变量。
结构初始化:
struct date={12,3,2021};//注意顺序
struct thismonth={.month=3,.year=2021};//剩下没有被赋值的部分都是0,和数组一样

和数组相比,结构中的成员可以是不同类型的。
数组用[]运算符和下标来访问;而结构用.运算符和名字来访问。
结构的运算
可以用结构名字.成员名字来访问某个成员,也可以直接用结构名字来访问整个结构变量。可以做赋值、取地址,传递给函数参数。

p1=(struct point){5,10};
p1=p2;

这两种操作,数组变量都做不了。

struct date today,day;
today=(struct date){12,3,2021};
day=today;

和数组不同,结构变量的名字并不是结构变量的地址,取地址要加上&

struct date *pdate=&today;

11.2.2 结构与函数

结构像int等类型一样,可以作为函数的参数。

int numberofdays(struct date d)

整个结构可以作为参数的值传入函数。这时候会在函数内部新建一个结构变量,并复制该参数的值。当然,函数也可以返回一个结构。
(貌似美国的写法是月/日/年)
&date.month中,取成员运算符.的优先级高于取地址运算符&

怎样输入结构?我们不能用scanf直接读入一个结构。
先尝试写一个读入结构的函数:先在main函数里定义,然后把该参数传入getstruct函数

struct point p={0,0};
gtestruct(p);

void getstruct(struct point p){
	scanf("%d",&p.x);
	scanf("%d",&p.y);
}

然而这不像指针,这样读入的结构是不会传入原函数中的。(只是一个克隆体而不是直接对结构本身做操作)
记住函数是有返回值的,我们要做的是在输入函数中创建一个临时的结构变量,返回给调用者。

struct point getstruct(void)
{
struct point p;
	scanf("%d",&p.x);
	scanf("%d",&p.y);
	return p;
}
//main函数中:y=getstruct();

然而,在函数中建立一个拷贝来回传递,既费空间又费时间。还是结构指针的方法会好很多。

struct date myday;
struct date *p=&myday;
(*p).month=12;//正常应该这样写
p->month=12;//也可以简写成这样

->表示指向结构变量中的成员

#include<stdio.h> 
struct point{
	int x;
	int y;
}p;

struct point *getstruct(struct point *p);
void print(const struct point *p);

int main()
{
	struct point p={0,0};
	print(getstruct(&p));
	return 0; 
}

struct point *getstruct(struct point *p)
{
	scanf("%d",&p->x);
	scanf("%d",&p->y);
	return p;
}//像这样传入一个参数,对其做处理后再返回该参数的函数,可以直接套用在其他函数中。

void print(const struct point *p)//const
{
	printf("%d %d",p->x,p->y);
}

11.2.3 结构中的结构

结构中的数组

struct date dates[100];
struct date dates[]={
	{3,21,2021},{3,22,2021}
};
printf("%.2i",dates[1].month);//不知道%.2i什么意思

结构里的变量也可以是另外一个结构

struct point{
	int x;
	int y;
}
struct rectangle{
	struct point pt1;
	struct point pt2;
}
//如果有这样的定义:
struct rectangle r;
/*则可以有:
r.pt1.x;
r.pt1.y;
r.pt2.x;
r.pt2.y;
*/
//如果有这样的定义:
struct rectangle *rp;
rp=&r;
//那么下面的四种形式是等价的
r.pt1.x
rp->pt1.x
(r.pt1).x
(r->pt1).x
//但是不能写r->pt1->x,因为pt1不是指针而是结构。

在这里插入图片描述
如上图所示,rp指向r。
甚至可以做结构里的结构里的数组。
在这里插入图片描述

在这里插入图片描述
(这里也能看出这么写会好看很多~)

11.3.1 类型定义

比如我们之前讲struct的时候要一直加上struct前缀。如何摆脱呢?
自定义数据类型(typedef)
typedef int length;
这样使得length成为int类型的别名。可以直接把length当做int类型来用
length a,b;
length a[10];
声明的新类型是某种类型的别名,改变了程序的可读性,简化了复杂的名字。

typedef struct ADate{
int month;
int day;
int year;
}Date;

Date a={3,24,2021};
typedef *char[10] String;//string是十个字符串的数组的类型。

11.3.2 联合

union,表面上与struct非常相似。

unit xxx{
int a;
char b;
}xxx1,xxx2;

xxx1.a=1;
xxx2.b='c';

和struct不同的是,union中所有变量(即a,b)占据的是相同的空间,大家联合起来使用同一个空间。
比如一个int 4个字节,也可以被看做是char的数组0~3
比如char是1234,则转化为十六进制应该是00 00 04 D2
我们通过下面的方法来看看是不是这么储存的。
在这里插入图片描述
占位符的意思是:1.输出两位,即如果不足10要补个0(比如2→02)
2.这就是一个字节了,不要再扩展了
3.以十六进制输出
这个在文件那里还会再讲。
我们现在的X86是小端机器,放数的时候其实是小端在前
也是很有用的,比如做文件时,比如当我们要把一个整数以二进制形式输到一个文件中去时,可以作为中间的媒介(没懂……)。

<think>嗯,用户想了解C语言中匿名枚举的用法,特别是匿名枚举的使用方法和示例。首先,我需要回忆一下C语言枚举的基本知识,然后看看匿名枚举和普通枚举的区别。 根据之前的引用资料,枚举在C语言中用于符号化数字,提高代码可读性。普通枚举需要先定义类型,再声明变量,比如enum Color { RED, GREEN, BLUE }; enum Color c = RED;。而匿名枚举可能不需要定义类型名,直接使用枚举成员的值,这应该就是匿名枚举的特点。 用户的问题是关于匿名枚举的使用方法,我需要确定C语言是否支持匿名枚举。根据C标准,C语言中的枚举必须要有标签或者变量,但有时候可以通过省略标签来创建匿名枚举,同时声明变量。例如:enum { RED, GREEN, BLUE } color; 这里的color变量就是这个匿名枚举类型的实例。这种情况下,枚举没有类型名,所以之后不能再定义其他同类型的变量,但color可以直接使用REDGREEN等值。 接下来需要举出示例,说明匿名枚举的典型用法。比如在结构体中定义常量,或者在全局作用域中定义一组常量。例如: struct Config { enum { MAX_SIZE = 100, TIMEOUT = 30 }; int size; }; 这样,结构体中的MAX_SIZE和TIMEOUT可以作为常量使用。但要注意,这可能不是所有编译器都支持,尤其是旧版本的编译器,所以可能需要使用更通用的方法,比如在全局作用域中定义匿名枚举常量: enum { BUFFER_SIZE = 1024, MAX_USERS = 50 }; 这样,BUFFER_SIZE和MAX_USERS就可以作为整型常量使用,而无需指定枚举类型名。 另外,用户可能遇到的问题包括作用域问题,比如匿名枚举的成员是否会影响其他同名常量,或者如何在不同的作用域中使用匿名枚举。需要提醒用户注意枚举成员的作用域,比如在结构体内部定义的匿名枚举成员可能只在该结构体内有效,或者在全局作用域中定义的可能会污染全局命名空间。 还要注意匿名枚举与普通枚举的区别,匿名枚举通常用于一次性的变量或常量定义,无法复用类型,而普通枚举可以多次声明变量。此外,匿名枚举的成员在C语言中是作为整型常量存在的,可以直接使用,不需要通过枚举变量来访问。 可能用户在使用匿名枚举时遇到编译错误,比如重复定义或者作用域问题,需要给出解决方法,比如检查是否有重复的枚举成员名称,或者确认编译器是否支持匿名枚举的某些特性。 总结回答结构:先解释匿名枚举的概念,与普通枚举的区别,使用场景,然后给出具体的使用示例,包括全局作用域、结构体内、与宏定义的对比,最后说明注意事项和常见问题。</think>### C语言匿名枚举使用方法详解 #### 一、基本概念 匿名枚举**没有明确类型名称的枚举类型**,常用于定义**一次性使用的整型常量集合**。与普通枚举不同,它**直接声明常量值而不创建可复用的枚举类型**[^1]。 #### 二、核心语法 ```c // 匿名枚举标准语法 enum { 常量1 = 值1, 常量2 = 值2, //... } 变量名; // 可选变量声明 ``` #### 三、典型使用场景 1. **全局作用域常量定义** ```c enum { MAX_BUFFER = 1024, TIMEOUT_MS = 5000 }; // 直接使用常量 char buffer[MAX_BUFFER]; ``` 2. **结构体/联合体内置常量** ```c struct NetworkConfig { enum { MIN_PORT = 1024, MAX_PORT = 65535 }; int current_port; }; ``` 3. **替代宏定义** ```c // 优于 #define ERROR_CODE 1 enum { ERROR_CODE = 1, SUCCESS_CODE = 0 }; ``` #### 四、完整示例 ```c #include <stdio.h> // 定义匿名枚举常量 enum { LOG_DEBUG = 1, LOG_WARNING = 2, LOG_ERROR = 4 }; int main() { int log_level = LOG_DEBUG; switch(log_level) { case LOG_DEBUG: printf("Debug mode activated\n"); break; case LOG_WARNING: printf("Warning mode\n"); break; case LOG_ERROR: printf("System error!\n"); break; } return 0; } ``` #### 五、注意事项 1. **作用域规则**枚举常量具有**与声明位置匹配的作用域**(全局/局部) 2. **类型安全**:C语言枚举本质是int类型,匿名枚举不提供额外类型检查 3. **编译器差异**:部分旧编译器(如C89)可能要求枚举必须关联变量名 4. **常量冲突**:避免与其他作用域的同名常量产生冲突 #### 六、与普通枚举对比 | 特性 | 匿名枚举 | 普通枚举 | |-----------------|---------------------|---------------------| | 类型名称 | 无 | 需要明确声明 | | 作用域 | 声明位置决定 | 类型全局可见 | | 重复使用性 | 单次使用 | 可多次实例化 | | 内存占用 | 无类型元数据 | 包含类型信息 | #### 七、常见问题解决 **问题1:出现"redeclaration of enumerator"错误** ```c enum { A = 1 }; enum { A = 2 }; // 错误!重复定义 ``` **解决方案**:统一管理全局常量定义 **问题2:结构体内匿名枚举访问失败** ```c struct S { enum { SIZE=100 }; }; printf("%d", SIZE); // 错误!应使用struct S::SIZE (C++语法) ``` **C语言解决方案**: ```c printf("%d", (struct S){0}.SIZE); // 通过临时变量访问 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰海宽松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值