当前位置: 首页 > news >正文

C语言 共用体和typedef

 

目录

共用体概述

声明共用体

声明共用体变量

调用共同体变量的成员

->操作符

为什么使用typedef

typedef使用格式

举 例


共用体概述

有时需要一种数据结构,不同的场合表示不同的数据类型。比如, 如果只用一种数据结构表示学生的“成绩”,这种结构就需要有时是 整数(80、90),有时是字符('A'、'B'),又有时是浮点数(80.5、60.5)。

C 语言提供了共用体类型(Union 结构),用来自定义可以灵活变更的 数据结构。它内部可以包含各种属性,但同一时间只能有一个属 性,因为所有属性都保存在同一个内存地址,后面写入的属性会覆 盖前面的属性。这样做的最大好处是 节省内存空间 。

“共用体”与“结构体”的定义形式相似,但它们的含义是不同的。

结构体变量所占内存长度是各成员占的内存长度之和;每个成员 分别占有其自己的内存单元。

共用体变量所占的内存长度等于最长的成员的长度;几个成员共 用一个内存区。

声明共用体

格式:

union 共用体类型名称{
    数据类型 成员名1;
    数据类型 成员名2;
    …
    数据类型 成员名n;
};

举例:

union Data {
    short m;
    float x;
    char c;
};

上例中, union 命令定义了一个包含三个属性的数据类型 Data。虽 然包含三个属性,但是同一时间只能取到一个属性。最后赋值的属 性,就是可以取到值的那个属性。

声明共用体变量

方式1:先定义共用体类型,再定义共用体变量

union Data {
    short m;
    float x;
    char c;
};
int main()
{
    union Data data1;
}

方式2:定义共用体类型的同时定义共用体变量

union Data1
{
    short a;
    float b;
    char c;
}data2,data3;

以共用体变量a为例,它由3个成员组成,分别是m、x和c,编译 时,系统会按照最长的成员为它分配内存,由于成员x的长度最长, 它占4个字节,所以共用体变量a的内存空间也为4个字节。

union
{
    short m;
    float x;
    char c;
} a, b;

int main()
{
    printf("%d\n",sizeof(a));  //只取最长的float,4个字节
    return 0;
}

调用共同体变量的成员

#include <stdio.h>

union Data
{
    short a;
    float b;
    char c;
};

int main()
{
    //方式1
    data.a = 12;
    
    //方式2
    union Data data4 = {.a = 12};
    
    //方式3
    union Data data5 = {12};//可以理解为给首元素赋值(默认)
    
    //错误的方式
    union Data data6 = {.a = 12,.b = 12.3F,.c = 'A'};
    printf("%c\n",data6.c);//输出的是A
    printf("%f\n",data6.b);//输出是0.000000
}

->操作符

#include <stdio.h>

union Data
{
    short a;
    float b;
    char c;

}

int main()
{
    union Data data1;

    data1.a = 12;
    
    union Data *data_ptr;

    data_ptr = &data1;

 // ->符号的使用:针对的是共用体指针变量的使用
    
    printf("%d \n",data1.a);
    printf("%d \n",(*data_ptr).a);
    printf("%d \n",data_ptr->a);  
}

补充说明:

不能对共用体变量名赋值,也不能企图引用变量名来得到一个 值。只能引用共用体变量中的成员。

C99允许同类型的共用体变量互相赋值。

printf("%d",a);   //错误的
printf("%d",a.i); //正确的

 C99允许用共用体变量作为函数参数。

b = a; //a和b是同类型的共用体变量,合法

共用体类型可以出现在结构体类型定义中,也可以定义共用体数 组。反之,结构体也可以出现在共用体类型定义中,数组也可以 作为共用体的成员。

题目:现有一张关于学生信息和教师信息的表格。 学生信息包括姓名、编号、性别、职业、分数; 教师的信息包括姓名、编号、性别、职业、教学科目。 请看下面的表格,请使用共用体编程完成。

#include <stdio.j>
#include <stdlib.h>

sttuct Person
{
    char name[20];
    int id;
    char gender;
    char profession;
    union
    {
        float score;
        char course;
    }sc;
    
};

int main()
{
    int i;
    struct Person person[n];
    for(i=0;i<n;i++)
    {
        printf("%s %d %s %s \n",person[i].name,&person[i].id,person[i].gender);
        if (persons[i].profession == 's')
        {
            //如果是学生
        printf("请输入学生成绩:");
        scanf("%f", &persons[i].sc.score);

        } 
      else 
        { 
            //如果是老师
         printf("请输入老师课程:");
        scanf("%s", persons[i].sc.course);

        }
}

为什么使用typedef

C语言允许为一个数据类型起一个新的别名,就像给人起“绰号”一 样。

起别名的目的不是为了提高程序运行效率,而是为了 编码方便 。例 如,有一个结构体的名字是 student,定义一个结构体变量stu1,代 码如下:

struct student stu1;

typedef使用格式

用typedef声明数组类型、指针类型,结构体类型、共用体类型等, 使得编程更加方便。

1、为某个基本类型起别名

//1.场景1:给基本数据类型起别名
typedef int Integer;

typedef unsigned char Byte;

//测试1:
    int i = 10;
    Integer j =10;

    unsigned char c1 = 10;
    Byte c2 = 10;

2、为结构体、共用体起别名

//2.场景2:给结构体、共用体起别名
//写法1
struct student
{
    char nane[20];
    int age;
};
typedef struct student MyStudent;//或者放上面做全局变量

//写法2
typedef struct //匿名结构体
{
    char name[20];
    int age;

}MyDog;

typedef union Date
{
    char c;
    float f;
    short s;
}MyDate;

//测试2
    typedef struct student MyStudent;

    struct student s1;
    MyStudent s2;

    //struct Dog dog1;
    MyDog dog2;

    union Date data1;
    MyDate data2;

3、为指针起别名

//3.场景3:给指针类型起别名

typedef int * INT_PTR;//别名是INT_PTR对应是int类型的指针

typedef char * String;

//测试3

    int num = 10;
    int * int_ptr1;
    int_ptr1 = &num;
    printf("&d \n",*int_ptr1);
    
    INT_PTR int_ptr2;
    int_ptr2 = &num;
    printf("&d \n",*int_ptr2);
    
    char * str1 = "hello";
    String str2 = "hello";

4、为数组类型起别名

//4.场景4:给数组类型起别名

typedef int five_ints[5];//别名就是five_ints对应的是长度为5的int类型数组

typedef int * PTR_INTS[2];//PTR_INTS是int * [2]的别名

//测试4
    int arr[5] = {1,2,3,4,5};
    five_ints arr2 = {1,2,3,4,5};
    
    //测试指针数组
    int a = 10,b = 20;
    int * arr3[2] = {&a,&b};
    
    PTR_INTS arr4 = {&a,&b};

5.为函数类型起别名

//5.场景5:给函数类型起别名

typedef int (*PTR_FUNC)(int,int);// 别名就是PTR_FUNC对应的是两个形参是int而且返回值也是int的类型的函数指针(可以理解成给指针起了别名)

int max(int a,int b)
{
    int c = (a > b)? a : b;
    return c;
}

int min(int a,int b)
{
    int c = (a < b)? a : b;
    return c;
}

//测试5
    //复习:函数指针的使用
    
    int (*ptr_compare)(int,int);
    ptr_compare = &max;
    //调用函数指针对应的函数
    int result = (*ptr_compare)(10,15);//先取结果=max,再赋俩值,再返回int值
    
    printf("%d ",result);
    
    //使用别名
    PTR_FUNC ptr_func = &min;
    int result1 = (*ptr_func)(12,24);
    
    printf("%d",result1);

举 例

#include <stdio.h>

//函数

int add(int m,int n)
{
    int sum = m + n;

    return sum;
}

//数组

char str[3][30] ={"烧肉","123","12581"};



//使用typedef
typedef int (*PTR_FUNC)(int,int);//现在是一个类型

typedef char (*PTR_ARR)[30];



int main()
{
    //调用函数 : 使用函数指针
    int (*ptr_add)(int,int);
    ptr_add = &add;
    int sum = (*ptr_add)(10,20);
    printf("sum = %d\n",sum);

    //遍历数组:使用数组指针
    //char *ptr_arr[30];//定义了一个指针数组,数组长度是30,每个元素是指针

    char (*ptr_arr)[30];//定义了一个数组指针,这个指针指向了长度30的char类型数组

    ptr_arr = str;//将str[0]的首地址赋给ptr_arr指针

    for(int i = 0;i <3;i++)
    {
        printf("str[%d]: %s \n",i,*(ptr_arr+i));

    }

    //##############使用typedef声明的类型进行调用##############

    //调用函数

    PTR_FUNC ptr_add1 = &add;

    int sum1 = (*ptr_add1)(100,200);
    printf("sum1 = %d\n",sum1);


    //遍历数组
    PTR_ARR ptr_arr1 = str;

    for(int i = 0;i <3;i++)
    {
        printf("str[%d]: %s \n",i,*(ptr_arr1+i));

    }

    return 0;
}

小 结

(1) typedef的方法实际上是为特定的类型指定了一个同义字 (synonyms)。

(2) 用typedef只是对已经存在的类型指定一个新的类型名,而没有创 造新的类型。

(3) typedef与#define是不同的。#define是在 预编译时处理 的,它只 能作简单的字符串替换,而typedef是在 编译阶段处理 的,且并非 简单的字符串替换。

(4) 当不同源文件中用到同一类型数据(尤其是像数组、指针、结构 体、共用体等类型数据)时,常用typedef 声明这些同一的数据类 型。

技巧:可以把所有的typedef名称声明单独 放在一个头文件 中,然 后在需要用到它们的文件中用#include指令把它们包含到文件中。这 样编程者就不需要在各文件中自己定义typedef名称了。

(5) 使用typedef名称有利于 程序的通用与移植 。有时程序会依赖于 硬件特性,用typedef类型就便于移植。 某一个值在不同计算机上的类型,可能是不一样的。

int i = 100000;

 上面代码在32位整数的计算机没有问题,但是在16位整数的计算机 就会出错。C 语言的解决办法,就是提供了类型别名,在不同计算 机上会解释成不同类型,比如 int32_t 。

int32_t i = 100000;

上例将变量 i 声明成 int32_t 类型,保证它在不同计算机上都是32位 宽度,移植代码时就不会出错。

这一类的类型别名都是用 typedef 定义的。下面是类似的例子。

typedef long int ptrdiff_t;
typedef unsigned long int size_t;
typedef int wchar_t;

 这些整数类型别名都放在头文件 stdint.h ,不同架构的计算机只需 修改这个头文件即可,而无需修改代码。

 

相关文章:

  • 集群搭建Weblogic服务器!
  • C++学习之金融类安全传输平台项目git
  • 第十五届蓝桥杯C/C++B组省赛真题讲解(分享去年比赛的一些真实感受)
  • 智体知识库:poplang编程语言是什么?
  • 具身机器人中AI(DEEPSEEK)与PLC、驱动器协同发展研究:突破数据困境与指令精确控制(1)
  • System 应用访问 Vendor 库的详细方案
  • 如何将数组转换为对象(键为数组元素,值为 true)
  • 用 Vue 3 + D3.js 实现动态数据流图
  • noscript 标签是干什么的
  • Linux上位机开发实践(关于Qt的移植)
  • 具身智能零碎知识点(三):深入解析 “1D UNet”:结构、原理与实战
  • Python_levl2.3函数
  • 【AutoTest】自动化测试工具大全(Python)
  • 限流、降级、熔断、隔离?
  • 【Hyperlane 】轻松实现大文件分块上传!
  • 六、测试分类
  • Python中NumPy的逻辑和比较
  • API 请求失败时的处理方法
  • 如何使用MaxScript+dotNet在UI中显示图像?
  • 大模型LLM表格报表分析:markitdown文件转markdown,大模型markdown统计分析
  • 网站后期维护怎么做/最简单的营销方案
  • 济南网站开发企业/网络营销方案
  • 腾云建站官网/2345网址导航是什么浏览器
  • 免费空间做网站/seo实战密码第三版
  • 建设网站费用会计分录/工具seo
  • 微信公众号做的网站/宁波seo快速优化教程