目录
下一篇:c语言全局变量与静态本地变量
结构类型
一个结构是一个复合的数据类型
声明例子:
struct date{
int month;
int day;
int year;
};分号不能漏
创建变量
struct date today;
赋值:
today.month=07;
today.day=31;
today.year=2014;
打印:
printf("Today is date is %i-%i-%i.\n",
today.year,today.month,today.day);
注意:以上的结构声明在函数内部,则是个本地变量,通常在函数外部声明结构类型,这样就可以被多个函数所使用了
使用结构:struct 结构的名字 变量名;
另一种结构体的声明方式
struct{ //这个结构没有名字
int x;
int y;
}p1,p2; //p1和p2都是这个无名结构的变量
p1和p2都是一种无名结构,里面有x和y
这么写是不想在长远的将来还用这种结构
最常见的写法
struct point{
int x;
int y;
}p1,p2;
p1和p2都是point结构的变量
结构的初始化
struct date{
int month;
int day;
int year;
};
//第一种初始化方式,依次赋值
struct date today={07,31,2014};
//第二种初始化方式,变量.属性=值
struct date thismonth={.month=7,.year=2014};
printf("Today is date is %i-%i-%i.\n",
today.year,today.month,today.day);
printf("This month is date is %i-%i-%i.\n",
thismonth.year,thismonth.month,thismonth.day);
发现没有给的值填入了0
结构成员
结构和数组有点像
结构用.运算符和结构变量名字访问其成员
例如:
today.day
sturent.firstName
p1.x
p1.y
结构名.是没有任何意义的
结构运算
要访问整个结构,直接用结构变量的名字
对于整个结构,可以做赋值、取地址,也可以传递给函数参数
p1=(struct point){5,10}; //相当于p1.x=5;p1.y=10; 前面的小括号是类型转换
p1=p2; //相当于p1.x=p2.x;p1.y=p2.y;
而数组无法做这用运算
struct date today;
today=(struct date){07,31,2014};
struct date day=today;
printf("Today is date is %i-%i-%i.\n",
today.year,today.month,today.day);
printf("This day is date is %i-%i-%i.\n",
day.year,day.month,day.day);
我们再给today的year赋值2015,分别打印today和day的year
today.year=2015;
printf("%d\n",today.year);
printf("%d\n",day.year);
发现结果不一样,说明这两个结构变量不是一样的东西。
结构指针
结构和数组最不一样的地方,结构变量的名字并不是结构变量的地址,必须使用&运算符
struct date *pDate =&today
struct date *pDate=&today;
printf("today 的地址是:%p\n",pDate);
结构与函数
结构作为函数参数
int numberOfDays(struct date d)
整个结构可以作为参数的值传入函数
这时候是在函数内新建一个结构变量(也和数组不一样),并复制调用者的结构的值
当然也可以返回一个结构
注意:scanf("%i,&today.month") 当中的&today.month,是先取today.month 再做的取地址
不然要是先取的是地址,则一个指针做.运算符是无意义的
所以去成员.运算符,优先级高于取地址&
输入结构
没有直接的方式可以一次scanf一个结构
struct point{
int x;
int y;
};
void getStruct(struct point);
void output(struct point);
int main(int argc,char const * argv[])
{
struct point y={0,0};
getStruct(y);
output(y);
return 0;
}
void getStruct(struct point p){
scanf("%i",&p.x);//输入1
scanf("%i",&p.y);//输入1
printf("%i,%i\n",p.x,p.y);//输出1,1
}
void output(struct point p){
printf("%i,%i",p.x,p.y);//输出0,0
}
为什么?因为传递到函数中的的并不是结构变量本身,记住c在调用函数调用时是传值的,所以这么定义一个输入函数是不行的
那应该怎么做?
解决方案
1、将临时结构体返回给调用者
2、用结构指针(最为推荐)
指向结构的指针
struct date *p=&myday
这么定义一个指针后可以通过一个更为简单的方式访问结构成员
p->month=12; //等同于(*p).month这么写就太麻烦了
struct point{
int x;
int y;
};
struct point* getStruct(struct point *p);
void output(struct point);
void print(const struct point *p);
int main(int argc,char const * argv[])
{
struct point y={0,0};
getStruct(&y);//这次没有获取返回值
output(y);
print(getStruct(&y));//这次利用了返回的指针
return 0;
}
struct point* getStruct(struct point *p){
scanf("%i",&p->x);
scanf("%i",&p->y);
printf("%i,%i\n",p->x,p->y);
}
void output(struct point p){
printf("%i,%i",p.x,p.y);
}
void print(const struct point *p){
printf("%i,%i",p->x,p->y);
}
改进
struct point{
int x;
int y;
};
struct point* getStruct(struct point *p);
void output(struct point);
void print(const struct point *p);
int main(int argc,char const * argv[])
{
struct point y={0,0};
getStruct(&y);//这次没有获取返回值
output(y);
output(*getStruct(&y));
print(getStruct(&y));//这次利用了返回的指针
//更邪恶的事情,将返回的指针当做左值,取*并赋值
*getStruct(&y)=(struct point){1,2};
return 0;
}
struct point* getStruct(struct point *p){
scanf("%i",&p->x);
scanf("%i",&p->y);
printf("%i,%i\n",p->x,p->y);
}
void output(struct point p){
printf("%i,%i\n",p.x,p.y);
}
void print(const struct point *p){
printf("%i,%i\n",p->x,p->y);
}
结构体中的结构
一、结构数组
struct date dates[100];
struct date dates[]={
{4,5,2005},{2,4,2005}
}
以上就是结构数组,有结构体组成的数组
可以通过这样访问数组中结构变量的成员变量:date[1].month,date[0].year
二、结构中的结构
struct dateAndTime{
struct date sdate;//结构里面的成员结构
struct date stime;
};
struct point{
int x;
int y;
};
struct rectangle{
//用结构表达一个矩形,需要两个点
struct point pt1;//点1
struct point pt2;//点2
};
struct rectangle r;
//可以有
r.pt1.x;
r.pt1.y;
r.pt2.x;
r.pt2.y;
struct rectangle *rp;
rp=&r;
//一下4这种方式等价
r.pt1.x;
rp->pt1.x;
(r.pt1).x;
(rp->pt1).x;
//没有这种东西rp->pt1->x,pt1不是指针
//有意思的来了,将上面的矩形结构,写个数组,初始化就要套很多{}
struct rectangle rects[]={
{
{1,2},{3,4}},{
{5,6},{7,8}}};
类型定义
每次用结构都要带一个struct,太麻烦
typedef关键字 自定义数据类型
来声明一个已有的数据类型的新名字
例如:
typedef int Length;
使得Length成为int类型的别名
这样Length这个名字就可以代替int出现在变量定义和参数声明的地方了
例如:Length a,blen;
Length numbers[10];
这段代码,通过typedef改善了程序的可读性
重载了已有的类型名字,新的名字的含义更清晰,具有可移植性
还可以简化复杂的名字
例如这个东西
typedef struct {
int month;
int day;
int year;
}Date;
是定义了一个没有名字的结构体,但typedef可以将其命名为Date
所以typedef语句后面最后一个单词才是名字
联合
一、定义:联合的关键字union,看起来和struct是一样的
union AnElt{
int i;
char c;
}elt1,elt2;
elt1.i=4;
elt2.c='a';
elt2.i=0xDEADBEEF;
它和和struct不同的是,struct里面的成员变量是分开的,要访问哪个就是哪个
但对于union,任何的成员变量都占据了相同的空间
二、什么场合用?
typedef union {
int i;
char ch[sizeof(int)];
}CHI;
int main(int argc,char const * argv[])
{
CHI chi;
chi.i=1234;//对应16进制04D2
for (int i = 0; i < sizeof(int ); ++i) {
printf("%02hhX",chi.ch[i]);//%0xhhX大概表示显示为两个16进制,一个字节大小,前面不足得补0
//输出D2040000和预想不一样,是相反的,因为x86架构的cpu低位在前(小端)
}
//这种用union的场合就是用这种方式得到一个整数(Double、float)内部的各个字节,可以用来做读写的媒介
printf("\n");
return 0;
}