当前位置 博文首页 > jtwqwq的博客:翁恺老师C语言程序设计网课(11)

    jtwqwq的博客:翁恺老师C语言程序设计网课(11)

    作者:[db:作者] 时间:2021-08-19 09:51

    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