C++程序设计——十七

C Struct和union

struct,结构体

我们已经对数组很熟悉了,它可以用来存储一组数据类型相同的数据,但实际上,我们常常需要的一组数据里面,数据类型很可能不同,比如,对于一个学生的信息,姓名为字符串,学号为整数,成绩为浮点数,这个时候,数组很难满足我们存储数据的需求,而这就引出了结构体的概念。
结构体是由用户自己指定的一种数据结构,它是多种类型数据的集合,以便引用,这些组合在一个整体中的数据是互相联系的,这样的数据结构称为结构体,语法如下

struct struct_name
{
	typename1 var1;
	typename2 var2;
};

我们可以看到,我们使用关键字struct来定义结构体,后面跟着结构体名称,结构体内容即为我们需要的数据成员。
我们来看一个示例

#include <stdio.h>

struct student
{
    char *name;
    int age;
    float socre;
}student1;



int main()
{
    struct//无名结构,常出现在main函数中
    {
        char *name;
        int age;
        int ID;
    }person1;
    student1.name="ming";
    student1.age=12;
    student1.socre=99.5;
    printf("学生的姓名为%s\n",student1.name);
    printf("学生的年龄为%d\n",student1.age);
    printf("学生的成绩为%.2f\n",student1.socre);

    person1.name="hong";
    person1.age=22;
    person1.ID=1234;
    
    printf("小红的姓名为%s\n",person1.name);
    printf("小红的年龄为%d\n",person1.age);
    printf("小红的身份证号为%d\n",person1.ID);

    //使用结构体名称定义新的结构体变量
    struct student s1={"a",13,99.6};

    printf("新学生的姓名为%s\n",s1.name);
    printf("新学生的年龄为%d\n",s1.age);
    printf("新学生的成绩为%.2f\n",s1.socre);

    return 0;
}

运行结果如下

学生的姓名为ming
学生的年龄为12
学生的成绩为99.50
小红的姓名为hong
小红的年龄为22
小红的身份证号为1234
新学生的姓名为a
新学生的年龄为13
新学生的成绩为99.60

定义结构体的两种方式

在示例代码中,我们看到了两种定义结构体的方式
第一种

struct struct_name
{
	//定义结构体成员
}结构体变量1={/*初始化结构体成员*/},结构体变量2;

第一种定义方式是我们前面提到的,后面可以紧接着定义该类型结构体的变量,也可以不定义,而是选择用struct关键字定义结构体变量,如下
struct struct_name s1={/*初始化结构体成员*/};
或者
struct strcut_name s1;
他表示定义struct_name类型的变量s1;

第二种结构体定义方式

struct
{
	//定义结构体成员
}结构体变量1={/*初始化结构体成员*/},结构体变量2;

第二种定义方式称作无名结构体,一般用于main函数,因为它没有结构体名称,所以它是一次性的,必须在定义结构体时在后面定义结构体变量,后面无法再定义相同类型的结构体变量。

应用在结构体上的函数

我们可以定义对结构体变量进行改变的函数,原理还是指针和取地址符,不再多说

#include <stdio.h>

struct student
{
    char *name;
    int age;
    int height;
};

void better(struct student* s)
{
    if((*s).age>20)
    {
        (*s).age=18;
    }
    if((*s).height<180)
    {
        (*s).height=180;
    }
}

int main()
{
    struct student ming={"ming",21,173};
    printf("原来的ming:\n");
    printf("姓名为%s\n",ming.name);
    printf("年龄为%d\n",ming.age);
    printf("身高为%d\n",ming.height);
    better(&ming);
    printf("\n变得更好后的ming:\n");
    printf("姓名为%s\n",ming.name);
    printf("年龄为%d\n",ming.age);
    printf("身高为%d\n",ming.height);
    return 0;
}

结果如下

原来的ming:
姓名为ming
年龄为21
身高为173

变得更好后的ming:
姓名为ming
年龄为18
身高为180

union,共用体/联合体

union和struct的关系

union是在某种程度上和结构体很类似的一种数据结构,它也同样是多种类型数据的集合。但他们也有明显的区别。

  • 在结构体中,所有成员变量可以同时存在,全面,所以很方便;但不管用不用这些成员变量,内存空间都会分配,容易造成浪费,特别是在内存比较紧张的情况下。
  • 在联合体中,虽然也可以定义多个成员变量,但同时只能有一个成员带有值,这就是它的缺点——不够包容;但优点就是内存使用更加精细灵活,节省内存。

为什么联合体是这样的?因为联合体的所有成员变量都是使用同一个内存位置来存储值,自然同一时间只能有一个成员变量有值。

定义union

我们使用union关键字来定义联合体,方式与定义结构体时类似。union 语句定义了一个新的数据类型,带有多个成员。union 语句的格式如下:

union union_name
{
	//定义成员变量
}联合体变量1,联合体变量2;

看一个示例

#include <stdio.h>

union person
{
    int age;
    int height;
}p1;

int main()
{
    union person p2={175};
    p1.age=13;
    p1.height=175;
    printf("年龄为%d,地址为%p\n",p1.age,&p1.age);
    printf("身高为%d,地址为%p\n",p1.height,&p1.height);

    // p2.height=175;
    // p2.age=13;
    printf("年龄为%d\n",p2.age);
    printf("身高为%d\n",p2.height);

    return 0;
}

执行结果如下

年龄为175,地址为0x555555558014
身高为175,地址为0x555555558014
年龄为175
身高为175

我们显然可以看到,成员变量age和height共用一个内存地址,并且各种变量名都可以同时使用,操作也是共同生效。
同时要注意的是,无法在定义联合体变量时同时赋值多个成员变量。

使用union来判断电脑是大端还是小端

#include<stdio.h>  
union var
{
    char c[4];
    int i;
};

int main()
{   
    union var data;
    data.c[0]=0x04;//因为是char类型,数字不要太大,算算ascii的范围~  
    data.c[1]=0x03;//写成16进制为了方便直接打印内存中的值对比  
    data.c[2]=0x02;
    data.c[3]=0x11;
    //数组中下标低的,地址也低,按地址从低到高,内存内容依次为:04,03,02,11。总共四字节!  
    //而把四个字节作为一个整体(不分类型,直接打印十六进制),应该从内存高地址到低地址看,0x11020304,低位04放在低地址上。  
    printf("%x\n",data.i);
}

输出为11020304,说明电脑为小端

union的本质

联合体union的本质是在内存中开辟一个足够大的空间,至于怎么放数据,放什么数据,不重要。
union的成员变量是相当于开辟了几个接口(即union包含的变量)!但是,没开辟也能用!

#include <stdio.h>
union u
{
    int i;
    double d;//这个union有8个字节大小
}uu;

int main()
{
    uu.i=10;
    printf("%d\n",uu.i);
    char *c;
    c=(char*)&uu;//把union的首地址赋值、强转成char类型
    c[0]='a';
    c[1]='b';
    c[2]='c';
    c[3]='\0';
    c[4]='d';
    c[5]='e';

    printf("%s\n",c);//利用结束符'\0'打印字符串"abc"
    printf("%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5]);

    return 0;
}

结果如下

10
abc
abcde

这个示例说明,联合体只是定义了int和double接口,只要获得地址,往里面扔什么数据都可以。这就是C语言的强大,这就是union的本质——只管开辟一段空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值