c语言结构类型、typedef和联合体

目录

结构类型

结构与函数

结构体中的结构

类型定义

联合

下一篇: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; //p1p2都是这个无名结构的变量

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->xpt1不是指针

 //有意思的来了,将上面的矩形结构,写个数组,初始化就要套很多{}

    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的场合就是用这种方式得到一个整数(Doublefloat)内部的各个字节,可以用来做读写的媒介

    printf("\n");

    return 0;

}

 

猜你喜欢

转载自blog.csdn.net/weixin_46919419/article/details/112550291
今日推荐