C语言学习-翁凯(第十一章笔记)
C语言第十一章
11.1.1 枚举
常量符号化
#include<stdio.h>
const int red=0;
const int yellow=1;
const int green=2;
int main(int argc,char const *argv[])
{
int color=-1;
char *colorName=NULL;
printf("请输入你喜欢的颜色的代码:");
scanf("%d",&color)
switch(color){
case red:colorNmae="red";break;
case yellow:colorName="yellow";break;
case green:colorName="green";break;
default: colorName="unknown";break;
}
printf("你喜欢的颜色是%s\n",colorName);
return 0;
}
枚举
#include<stdio.h>
enum COLOR {RED,YELLOW,GREEN};
int main(int argc,char const *argv[])
{
int color=-1;
char *colorName=NULL;
printf("请输入你喜欢的颜色的代码:");
scanf("%d",&color);
switch(color){
case RED:colorNmae="red";break;
case YELLOW:colorName="yellow";break;
case GREEN:colorName="green";break;
default: colorName="unknown";break;
}
printf("你喜欢的颜色是%s\n",colorName);
return 0;
}
-
用枚举而不是定义独立的const int变量 -
枚举是一种用户定义的数据类型,它用关键字enum以如下语法来声明: enum 枚举类型名字 {名字0,…,名字n}; -
枚举类型名字通常并不真的使用,要用的是在大括号里面的名字,因为它们就是常量符号,它们的类型是int,值则依次从0到n,如: enum colors {red,yellow,green}; -
就创建了三个常量,red的值是0,yellow是1,而green是2. -
当需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量值名字。
#include<stdio.h>
enum COLOR {RED,YELLOW,GREEN};
void f(enum color c);
int main(void)
{
enum color t=red;
scanf("%d",&t);
f(t);
return 0;
}
void f(enum color c)
{
printf("%d\n",c);
}
- 枚举量可以作为值
- 枚举类型可以跟上enum作为类型(例如enum color相当于int之类的类型)
- 但是实际上是以整数来做内部 计算和外部输出的
套路:自动计数的枚举
#include<stdio.h>
enum COLOR {RED,YELLOW,GREEN,NumCOLORS};
int main(int argc,char const *argv[])
{
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\n",colorName);
return 0;
}
- 这样需要遍历所有的枚举量或者需要建立一个用枚举量做下标的数组的时候就很方便了
枚举量
-
声明枚举量的时候可以指定值
enum COLOR {RED=1,YELLOW,GREEN=5}; #include<stdio.h>
enum COLOR {RED=1,YELLOW,GREEN=5};
int main(int argc,char const *agrv[])
{
printf("color for GREEN is %d\n",GREEN);
return 0;
}
枚举只是int #include<stdio.h>
enum COLOR {RED=1,YELLOW,GREEN=5,NumCOLORS};
int main(int argc,char const *agrv[])
{
enum COLOR color=0;
printf("color for GREEN is %d\n",GREEN);
printf("and color is %d\n",color);
return 0;
}
-
即使给枚举类型的变量赋不存在的整数值也没有任何warning或error
枚举
- 虽然枚举类型可以当作类型使用,但是实际上很(bu)少(hao)用
- 如果有意义上排比的名字,用枚举比const int方便
- 枚举比宏(macro)好,因为枚举有int类型
11.2.1 结构类型
声明结构类型
#include<stdio.h>
int main(int argc,char const *argv[])
{
struct date{
int month;
int day;
int year;
};
struct date today;
today.month=07;
today.day=31;
today.year=2014;
printf("Today`s date is %i-%i-%i.\n",today.year,today.month,today.day);
return 0;
}
在函数内/外?
#include<stdio.h>
struct date{
int month;
int day;
int year;
};
int main(int argc,char const *argv[])
{
struct date today;
today.month=07;
today.day=31;
today.year=2014;
printf("Today`s date is %i-%i-%i.\n",today.year,today.month,today.day);
return 0;
}
- 和本地变量一样,在函数内部声明的结构类型只能在函数内部使用
- 所以通常在函数外部声明结构类型,这样就可以被多个函数所使用了
声明结构的形式
struct point{
int x;
int y;
};
struct point p1,p2;
p1和p2都是point里面有x和y的值
struct{
int x;
int y;
}p1,p2;
p1和p2都是一种无名结构,里面有x和y
(不太常见)
struct point{
int x;
int y;
}p1,p2;
p1和p2都是point里面有x和y的值t
对于第一和第三种形式,都声明了结构point。但是第二种形式没有声明point,只是定义了两个变量。
结构变量
struct date today;
today.month=06;
today.day=19;
today.year=2005;
结构的初始化
#include<stdio.h>
struct date{
int month;
int day;
int year;
};
int main(int argc,char const *argv[])
{
struct date today={07,31,2014};
struct date thismonth={.month=7,.year=2014};
printf("Today`s date is %i-%i-%i.\n",today.year,today.month,today.day);
printf("Today`s date is %i-%i-%i.\n",thismonth.year,thismonth.month,thismonth.day);
return 0;
}
结构成员
- 结构和数组有点像(数组每个单元类型相同,结构可以不同)
- 数组用[]运算符和下标访问其成员
- 结构用 . 运算符合名字访问其成员
- today.day
- student.firstName
- p1.x
- p1.y
结构运算
- 要访问整个结构,直接用结构变量的名字
- 对于整个结构,可以做赋值、取地址,也可以传递给函数参数(数组无法做这两种运算!)
p1=(struct point){5,10}; //相当于p1.x=5;p2.y=10;p1=p2 //相当于p1.x=p2.x;p1.y=p2.y;
结构指针
- 和数组不同,结构 变量的名字并不是结构变量的地址,必须使用&运算符
struct date *pDate=&today;
11.2.2 结构与函数
结构作为函数参数
int numberOfDays(struct date d)
- 整个结构可以作为参数的值传入函数
- 这时候是在函数内新建一个结构变量,并复制调用者的结构的值
- 也可以返回一个结构
- 这与数组完全不同
输入结构
-
没有直接的方式可以一次scanf一个结构 -
如果我们打算写一个函数来读入结构 -
如下:
#include<stdio.h>
struct point{
int x;
int y;
};
void getStruct(struct point);
void output(struct point);
void main(){
struct point y={0,0};
getStruct(y);
output(y);
}
void getStruct(struct point p){
scanf("%d",&p.x);
scanf("%d",&p.y);
printf("%d,%d\n",p.x,p.y);
}
void output(struct point p){
printf("%d,%d\n",p.x,p.y);
}
(getStruct里面的p是接收了y的值,只是内容跟y相同的结构变量,而无法返回回去,无法改变main里面的y)
- 但是读入的结构如何传送回来呢?
- 记住C在函数调用时是传值的
- 所以函数中的p与main中的y是不同的
- 在函数读入了p的数值之后,没有任何东西回到main,所以y还是{0,0}
解决的方案
- 之前的方案,把一个结构传入了函数,然后在函数中操作,但是没有返回回去
- 问题在于传入函数的是外面那个结构的克隆体,而不是指针
- 在这个传入函数中,完全可以创建一个临时的结构变量,然后把这个结构返回给调用者
void main()
{
struct point y={0,0};
y=inputPoint();
putput(y);
}
struct point inputPoint()
{
struct point temp;
scanf("%d",&temp.x);
scanf("%d",&trmp.y);
return temp;
}
#include<stdio.h>
struct point{
int x;
int y;
};
struct point getStruct(void);
void output(struct point);
int main(int argc,char const argv[]){
struct point y={0,0};
y=getStruct();
output(y);
}
struct point getStruct(void){
struct point p;
scanf("%d",&p.x);
scanf("%d",&p.y);
printf("%d,%d\n",p.x,p.y);
return p;
}
void output(struct point p){
printf("%d,%d\n",p.x,p.y);
}
结构指针作为参数
- K&R说过(p.131)
- “If a large structure is to be passed to a function,it is generally more efficient to pass a pointer than to copy the whole structure”
指向结构的指针
struct date{
int month;
int day;
int year;
}myday;
struct date *p=&myday;
(*p).month=12;
p->month=12;
结构指针参数
void main()
{
struct point y={0,0};
inputPoint(&y);
output(y);
}
struct point* inputPoint(struct point *p)
{
scanf("%d",&(p->x));
scanf("%d"$(p->y));
return pl
}
12.2.3 结构中的结构
结构数组
struct date dates[100];
struct date dates[]={{4,5,2005},{2,4,2005}};
结构中的结构
struct dataAndTime{
struct date sdate;
struct time stime;
};
嵌套的结构
struct point{
int x;
int y;
};
struct rectangle{
struct point pt1;
struct point py2;
};
struct rectangle r;
如果有变量定义:
struct rectangle r,*rp;
rp=&r;
那么下面的四种形式是等价的:
r.pt1.x
rp->pt1.x
(r.pt1).x
(rp->pt1).x
但是没有rp->pt1->x(因为pt1不是指针)
结构中的结构的数组
#include<stdio.h>
struct point{
int x;
int y;
};
struct rectangle{
struct point p1;
struct point p2;
};
void printRect(struct rectangle r)
{
printf("<%d,%d>to<%d,%d>\n",r.p1.x,r.px.y,r.p2.x,r.p2.y);
}
int main(int argc,char const *argv[])
{
int i;
struct rectangle rects[]={
{{1,2},{3,4}},
{{5,6},{7,8}}
};
for(i=0;i<1;i++)
printRect(rexts[i]);
}
11.3.1 类型定义
自定义数据类型(typedef)
-
C语言提供了一个叫做***typedef***的功能来声明一个已有的数据类型的新名字。比如:
使得***Length***成为***int***类型的別名。 -
这样,***Length***这个名字就可以代替int出现在变量定义和参数声明的地方了: Length a,b,len; Length numbers[10];
Typedef
声明新的类型的名字
typedef struct{
int month;
int day;
int year;
}Date;
typedef int Length;
typedef *char[10] Strings;
typedef struct node{
int data;
struct node *next;
}aNode;
或
typedef struct node aNode;
11.3.2 联合
联合
选择:
成员是
sizeof(union …)=
? sizeof(每个成员)的最大值
union AnElt{
int i;
char c;
}elt1,elt2;
elt1.i=4;
elt2.c='a';
elt2.i=OxDEADBEEF;
- 存储
- 所有的成员共享一个空间
- 同一时间只有一个成员是有效的
- union的大小是其最大的成员
- 初始化
union的用处
#include<stdio.h>
typedef union{
int i;
char ch[sizeof(int)];
}CHI;
int main(int argc,char const *argv[])
{
CHI chi;
int i;
chi.i=1234;
for(i=0;i<sizeof(int);i++){
printf("%02hhX",chi.ch[i]);
}
printf("\n");
return 0;
}
低位在前
|