第十一周:结构类型

简介: 你会坚持下来的对吗?希望C语言不会成为你跨进编程世界的拦路虎,而是你的启蒙语言,梦的开始

11.1-1枚举

常量符号化

  1. 用符号而不是具体的数字来表示程序中的数字

#include

constintred=0;

constintyellow=1;

constintgreen=2;

intmain(intargc, charconst*argv[])

{

   intcolor=-1;

   char*colorName=NULL;

   

   printf("请输入你喜欢的颜色的代码:");

   scanf("%d",&color);

   switch( color ){

           casered:colorName="red";break;

           caseyellow:colorName="yellow";break;

           casegreen:colorName="green";break;

           default:colorName="default";break;

   }

   printf("你喜欢的颜色是%d",colorName);

   

   return0;

}

枚举

  1. 用枚举而不是定义独立的const int变量

#include

enumCOLOR{RED,YELLOW,GREEN}; //枚举

intmain(intargc, charconst*argv[])

{

   intcolor=-1;

   char*colorName=NULL;

   

   printf("请输入你喜欢的颜色的代码:");

   scanf("%d",&color);

   switch( color ){

           caseRED:colorName="red";break;

           caseYELLOW:colorName="yellow";break;

           caseGREEN:colorName="green";break;

           default:colorName="default";break;

   }

   printf("你喜欢的颜色是%d",colorName);

   

   return0;

}

  1. 枚举是一种用户定义的数据类型,它用关键字enum 以如下语法来声明:
  1. enum 枚举类型名字{名字0,.....,名字n};
  2. 枚举类型名字可以省略
  1. 枚举类型名字通常并不真的使用,要用的是在大括号里的名字,因为它们就是常量符号,它们的类型是int,值则依次从0到n。如:
  1. enum colors{red,yellow,green};
  2. 这样就创建了3个常量,red的值是0,yellow的值是1,而green的值是2
  3. 当需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量名字

#include

enumcolor{ red,yellow,green};

voidf(enumcolorc);

intmain(void)

{

   enumcolort=red;

   

   scanf("%d",&t);

   f(t);

   

   return0;

}

voidf(enumcolorc)

{

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

}

  1. 枚举量可以作为值
  2. 枚举类型可以跟上enum作为类型
  3. 但是实际上是以整数来做内部计算和外部输入输出的

#include

enumCOLOR{RED,YELLOW,GREEN,NumCOLOR};

intmain(intargc, charconst*argv[])

{

   intcolor=-1;

   char*ColorNames[NumCOLOR] = {"red","yellow","green",};

   char*colorName=NULL;

   

   printf("请输入你喜欢的颜色的代码:");

   scanf("%d",&color);

   if( color>=0&&color<NumCOLORS ){

       colorName=ColorNames[color];

   }else{

       colorName="unknown";

   }

   printf("你喜欢的颜色是%s",colorName);

   

   return0;

}

  1. 这样需要遍历所有的枚举量或者需要建立一个用枚举量做下标的数组的时候就很方便
  2. 上面的套路:在进行枚举的时候最后面在放上一个数(NumCOLORS),这样就能够表示NumCOLORS前面有几个数了(例如里面有3个数,索引值到0-2,在后面加上一个数,索引值刚好等于实际我们想要表达的数量)

枚举量

  1. 声明变量可以指定值
  1. enum COLOR{RED = 1,YELLOW,GREEN = 5};

#include

enumCOLOR {RED=1; YELLOW,GREEN=5,NumberCOLORS};

intmain(intargc,charconst*argv[])

{

   printf("code for GREEN is %d\n",GREEN);

   

   return0;

}

//这样输出的话,会从1开始计数,YELLOW则变成1+1,然后到GREEN的5之前都会跳过了

枚举只是int

  1. 即使给枚举类型的变量赋不存在的整数值也没有任何warning或error

枚举

  1. 虽然枚举类型可以当作类型使用,但是实际上很(bu)少(hao)用
  2. 如果有意义上排比的名字,用枚举比const int方便
  3. 枚举比宏(macro)好,因为枚举有int类型,宏没有类型(宏我在后面会解释是啥)

11.2-1结构类型

声明结构类型

#include

intmain(intargc,charconst*argv[])

{

   structdate{

       intmonth;

       intday;

       intyear;

   };//声明在这里,最后要加上分号哦,这是在函数内部声明的,通常放在函数外面

   

   structdatetoday;//在这里我们定义了一个变量是today,类型是struct date的

   

   today.month=07;

   today.day=31;

   today.year=2014;

   

   printf("Today's date is %i-%i-%i.\n",today.year,today.month,today.day);

   

   return0;

}

//声明结构类型跟定义结构变量是两件事情哦

  1. 声明在函数内还是函数外?
  1. 和本地变量一样(就是局部变量),在函数内部声明的结构类型只能在函数内部使用
  2. 所以通常在函数外部声明结构类型,这样就可以被多个函数所使用了

structpoint{

   intx;

   inty;

};

structpointp1,p2;

p1和p2都是point

里面有x和y值//这是第一种声明方式

----------------------------------------------

struct{

   intx;

   inty;

}p1,p2;

p1和p2都是一种无名结构,里面有x和y  //这是第二种形式,没有名字(没有声明point)

   //只是定义了两个变量,因为作者并不打算接下来继续在其他地方去调用

   

--------------------------------------------------------

structpoint{

   intx;

   inty;

}p1,p2;

p1和p2都是point,里面有x和y的值t  //这是第三种声明方式

结构的初始化

#include

structdate{

   intmonth;

   intday;

   intyear;

};

intmain(intargc,charconst*argv[])

{

   structdatetoday= {07,31,2014};

   structdatethismonth= {.month=7,.year=2014};

   

   printf("Today's date is %i-%i-%i.\n",today.year,today.month,today.day);

   printf("This month is %i-%i-%i.\n",thismonth.year,thismonth.month,thismonth.day);

   //给的值会被填进去,没给的值跟数组一样默认为0

   return0;

}

结构成员

  1. 结构和数组有点像
  2. 数组用[]运算符和下标访问其成员
  1. a[0] = 10;
  1. 结构用.运算符和其名字访问其成员
  1. today.day
  2. student.firstName
  3. p1.x
  4. p2.y

结构运算

  1. 要访问整个结构,直接用结构变量的名字
  2. 对于整个结构,可以做赋值、取地址,也可以传递给函数参数
  3. p1 = (struct point){5,10}; //相当于p1.x = 5;p1.y = 10;
  4. p1 = p2;  //相当于p1.x = p2.x;p1.y = p2.y;
  5. 数组无法做这两种运算!但结构可以

结构指针

  1. 和数组不同,结构变量的名字并不是结构变量的地址,必须使用&运算符
  2. struct date *pDate = &today;

#include

structdate{

   intmonth;

   intday;

   intyear;

};

intmain(intargc,charconst*argv[])

{

   structdatetoday;

   

   today= (structdate){07,31,2014};

   

   structdateday;

   

   structdate*pDate=&today;  //指向地址

   

   printf("Today's date is %i-%i-%i.\n",today.year,today.month,today.day);

   printf("The day's date is %i-%i-%i.\n",day.year,day.month,day.day);

   

   printf("address of today is %p\n",pDate);

   

   return0;

}

11.2-2结构与函数

结构作为函数参数

int numberOfDays(struct date d)

  1. 整个结构可以作为参数的值传入函数
  2. 这时候是在函数内新建一个结构变量,并复制调用者的结构的值
  3. 也可以返回一个结构
  4. 跟数组完全不一样

#include

#include

structdate{

   intmonth;

   intday;

   intyear;

};

boolisLeap(structdated);

intnumberOfDays(structdated);

intmain(intargc,charconst*argv[]){

   structdatetoday,tomorrow;

   //输入今天的日期,月 日 年

   printf("Enter today's date (mm dd yyyy):");

   scanf("%i %i %i",&today.month,&today.day,&today.year);

   

   if( today.day!=numberOfDays(today)){

       tomorrow.day=today.day+1;

       tomorrow.month=today.month;

       tomorrow.year=today.year;

   }elseif( today.month==12 ){

       tomorrow.day=1;

       tomorrow.month=1;

       tomorrow.year=today.year+1;

   }else{

       tomorrow.day=1;

       tomorrow.month=today.month+1;

       tomorrow.year=today.year;

   }

   

   printf("Tomorrow's date is %i-%i-%i.\n",

   tomorrow.year,tomorrow.month,tomorrow.day);

   

   return0;

}

intnumberOfDays(structdated){

   intdays;

   

   constintdaysPerMonth[12] = {31,28,31,30,31,30,31,31,30,31,30,31};

       

       if(d.month==2&&isLeap(d))

           days=29;

       else

           days=daysPerMonth[d.month-1];

   

   returndays;

}

boolisLeap(structdated){

   boolleap=false;

   

   if((d.year%4==0&&d.year%100!=0) ||d.year%400==0 )

       leap=true;

   

   returnleap;

}

输入结构

  1. 没有直接的方式可以一次scanf——一个结构
  2. 如果我们打算写一个函数来读入结构
  3. 但是读入的结构如何送回来呢?
  4. C语言在函数调用时是传值的
  5. 在函数读入了p的数值之后,没有任何东西回到main,所以y还是{0,0}
  1. 解决方案
  2. 之前的方案,把一个结构传入了函数,然后在函数中操作,但是没有返回回去
  1. 问题在于传入函数的是外面那个结构的克隆体,而不是指针
  2. 传入结构和传入数组是不同的
  1. 在这个输入函数中,完全可以创建一个临时的结构变量,然后把这个结构返回给调用者

#include

structpoint {

   intx;

   inty;

};

voidgetStruct(structpoint);

voidoutput(structpoint);

intmain(intargc,charconst*argv[])

{

   structpointy= {0,0};

   getStruct(y);

   output(y);

}

voidgetStruct(structpointp)

{

   scanf("%d",&p.x);

   scanf("%d",&p.y);

   printf("%d,%d",p.x,p.y);

}

voidoutput(structpointp)

{

   printf("%d,%d",p.x,p.y);

}

结构指针作为参数

  1. K&R说过(p.131)

指向结构的指针

用->表示指针所指的结构变量中的成员

structdate{

   intmonth;

   intday;

   intyear;

}myday;

structdate*p=&myday;

(*p).month=12;

p->month=12;

//第九行跟第十行是一样的意思,第十行会更便捷

#include

structpoint {

   intx;

   inty;

};

structpoint*getStruct(structpoint*);

voidoutput(structpoint);

voidprint(conststructpoint*p);

intmain(intargc,charconst*argv[])

{

   structpointy= {0,0};

   getStruct(&y);

   output(y);

   output(*getStruct(&y));

   print(getStruct(&y));

   *getStruct(&y) = (structpoint){1,2};

}

structpoint*getStruct(structpoint*p)

{

   scanf("%d",&p->x);

   scanf("%d",&p->y);

   printf("%d,%d",p->x,p->y);

   returnp;

}

voidoutput(structpointp)

{

   printf("%d,%d",p.x,p.y);

}

voidprint(conststructpoint*p);

{

   printf("%d,%d",p->x,p->y);

}

11.2-3结构中的结构

结构数组

  1. struct date dates[100]; //这是在初始化数组
  2. struct date dates[] = {{4,5,2005},{2,4,2005}};

#include

structtime{

   inthour;

   intminutes;

   intseconds;

};

structtimetimeUpdate(structtimenow);

intmain(void){

   structtimetestTimes[5] = {

       {11,59,59},{12,0,0},{1,29,59},{23,59,59},{19,12,27}

   };

   inti;

   

   for(i=0; i<5; ++i){

       printf("Time is %.2i:%.2i:%.2i",

              testTimes[i].hour,testTimes[i].minutes,testTimes[i].seconds);

       

       testTimes[i] =timeUpdate(testTimes[i]);

       

       printf("...one second later it's %.2i: %.2i: %.2i\n",

              testTimes[i].hour,testTimes[i].minutes,testTimes[i].seconds);

   }

   

   return0;

}

structtimetimeUpdate(structtimenow){

   ++now.seconds;

   if(now.seconds==60 ){

       now.seconds=0;

       ++now.minutes;

       

       if(now.minutes==60 ){

           now.minutes=0;

           ++now.hour;

           

           if(now.hour==24 ){

               now.hour=0;

           }

       }

   }

}

structdateAndTime{

   structdatesdate;

   structtimestime;

};

嵌套的结构

structpoint{

   intx;

   inty;

};

structrectangle{

   structpointpt1;

   structpointpt2;

};

如果有变量structrectangler;

就可以有:

   r.pt1.x、r.ptl.y

   r.pt2.x、r.pt2.y

   

如果有变量定义:

   structrectangler,*rp;

   rp=&r;

那么下面的四种形式是等价的:(结构中的结构)

   r.pt1.x

   rp->pt1.x

   (r.pt1).x

   (rp->pt1).x

但是没有rp->pt1->x(因为pt1不是指针)

结构中的结构的数组

#include

structpoint{

   intx;

   inty;

};

structrectangle{

   structpointp1;

   structpointp2;

};

voidprintRect(structrectangler)

{

printf("<%d,%d> to <%d,%d>\n",r.p1.x,r.p1.y,r.p2.x,r.p2.y);

}

intmain(intargc,charconst*argv[])

{

   inti;

   structrectanglerects[] = {{{1,2},{3.4}},{{5,6},{7,8}}};//2 rectangles

   for(i=0;i<2;i++)printRect(rects[i]);

}

11.3-1类型定义

自定义数据类型(typedef)

  1. C语言提供了一个叫做typedef的功能来声明一个已有的数据类型的新名字
  2. 比如:typedef int Length;
  3. 使得Length成为int类型的别名
  4. 这样,Length这个名字就可以替代int出现在变量定义和参数声明的地方了:
  1. Length a,b,len;
  2. Length numbers[10];

Typedef

  1. 声明新的类型的名字
  1. 新的名字是某种类型的别名
  2. 改善了程序的可读性

typedeflongint64_t;   //重载已有的类型名字  新名字的含义更清晰  具有移植性

typedefstructADate{

   intmonth;

   intday;

   intyear;

}Date; //简化了复杂的名字

//在这里Date等价于struct ADate,Date代表了到达struct ADate之前的所有

int64_ti=10000000000;

Dated= {9,1,2005};

typedefintLength;//Length就等价于int类型

typedef*char[10]Strings;  //String是10个字符串的数组的类型

typedefstructnode{

   intdata;

   structnode*next;

}aNode;

typedefstructnodeaNode;//这样用aNode就可以替代struct node

11.3-2联合

联合

  1. 存储
  1. 所有的成员共享一个空间
  2. 同一时间只有一个成员是有效的
  3. union的大小是其最大的成员
  1. 初始化
  1. 对第一个成员做初始化

#include

typedefunion{

   inti;

   charch[sizeof(int)];

}CHI;

intmain(intargc,charconstargv[])

{

   CHIchi;

   inti;

   chi.i=1234;

   for( i=0;i<sizeof(int);i++){

       printf("%02hhX",chi.ch[i]);

   }

   printf("\n");

   

   return0;

}

//输出D20400,          1234的十六进制是0x04D2

//低位在前(相当于倒置),小端的方式

目录
相关文章
如何正确使用RestTemplate【三】
上篇文章我们说了POST请求和OPTIONS请求相关的方法,对其中的postForLocation方法和optionsForAllow方法进行了一个具体使用上的阐述。今天我们来学习RestTemplate中的PUT请求、DELETE请求、PATCH请求相关的方法,要相信厚积薄发,每天学习一点点。
180 0
如何正确使用RestTemplate【三】
|
前端开发 程序员 调度
元计算:《元计算破解生命密码》听课笔记
元计算:《元计算破解生命密码》听课笔记
|
3天前
|
人工智能 自然语言处理 Shell
深度评测 | 仅用3分钟,百炼调用满血版 Deepseek-r1 API,百万Token免费用,简直不要太爽。
仅用3分钟,百炼调用满血版Deepseek-r1 API,享受百万免费Token。阿里云提供零门槛、快速部署的解决方案,支持云控制台和Cloud Shell两种方式,操作简便。Deepseek-r1满血版在推理能力上表现出色,尤其擅长数学、代码和自然语言处理任务,使用过程中无卡顿,体验丝滑。结合Chatbox工具,用户可轻松掌控模型,提升工作效率。阿里云大模型服务平台百炼不仅速度快,还确保数据安全,值得信赖。
158153 24
深度评测 | 仅用3分钟,百炼调用满血版 Deepseek-r1 API,百万Token免费用,简直不要太爽。
|
5天前
|
人工智能 API 网络安全
用DeepSeek,就在阿里云!四种方式助您快速使用 DeepSeek-R1 满血版!更有内部实战指导!
DeepSeek自发布以来,凭借卓越的技术性能和开源策略迅速吸引了全球关注。DeepSeek-R1作为系列中的佼佼者,在多个基准测试中超越现有顶尖模型,展现了强大的推理能力。然而,由于其爆火及受到黑客攻击,官网使用受限,影响用户体验。为解决这一问题,阿里云提供了多种解决方案。
17039 37
|
13天前
|
机器学习/深度学习 人工智能 自然语言处理
PAI Model Gallery 支持云上一键部署 DeepSeek-V3、DeepSeek-R1 系列模型
DeepSeek 系列模型以其卓越性能在全球范围内备受瞩目,多次评测中表现优异,性能接近甚至超越国际顶尖闭源模型(如OpenAI的GPT-4、Claude-3.5-Sonnet等)。企业用户和开发者可使用 PAI 平台一键部署 DeepSeek 系列模型,实现 DeepSeek 系列模型与现有业务的高效融合。
|
5天前
|
并行计算 PyTorch 算法框架/工具
本地部署DeepSeek模型
要在本地部署DeepSeek模型,需准备Linux(推荐Ubuntu 20.04+)或兼容的Windows/macOS环境,配备NVIDIA GPU(建议RTX 3060+)。安装Python 3.8+、PyTorch/TensorFlow等依赖,并通过官方渠道下载模型文件。配置模型后,编写推理脚本进行测试,可选使用FastAPI服务化部署或Docker容器化。注意资源监控和许可协议。
1311 8
|
13天前
|
人工智能 搜索推荐 Docker
手把手教你使用 Ollama 和 LobeChat 快速本地部署 DeepSeek R1 模型,创建个性化 AI 助手
DeepSeek R1 + LobeChat + Ollama:快速本地部署模型,创建个性化 AI 助手
3417 117
手把手教你使用 Ollama 和 LobeChat 快速本地部署 DeepSeek R1 模型,创建个性化 AI 助手
|
8天前
|
人工智能 自然语言处理 API
DeepSeek全尺寸模型上线阿里云百炼!
阿里云百炼平台近日上线了DeepSeek-V3、DeepSeek-R1及其蒸馏版本等六款全尺寸AI模型,参数量达671B,提供高达100万免费tokens。这些模型在数学、代码、自然语言推理等任务上表现出色,支持灵活调用和经济高效的解决方案,助力开发者和企业加速创新与数字化转型。示例代码展示了如何通过API使用DeepSeek-R1模型进行推理,用户可轻松获取思考过程和最终答案。
|
5天前
|
人工智能 自然语言处理 程序员
如何在通义灵码里用上DeepSeek-V3 和 DeepSeek-R1 满血版671B模型?
除了 AI 程序员的重磅上线外,近期通义灵码能力再升级全新上线模型选择功能,目前已经支持 Qwen2.5、DeepSeek-V3 和 R1系列模型,用户可以在 VSCode 和 JetBrains 里搜索并下载最新通义灵码插件,在输入框里选择模型,即可轻松切换模型。
934 14
|
12天前
|
API 开发工具 Python
阿里云PAI部署DeepSeek及调用
本文介绍如何在阿里云PAI EAS上部署DeepSeek模型,涵盖7B模型的部署、SDK和API调用。7B模型只需一张A10显卡,部署时间约10分钟。文章详细展示了模型信息查看、在线调试及通过OpenAI SDK和Python Requests进行调用的步骤,并附有测试结果和参考文档链接。
1938 9
阿里云PAI部署DeepSeek及调用

热门文章

最新文章