自定义结构类型(结构体,枚举,联合体)

一.结构体

1.定义结构体类类型

struct class
{
    int number;
    char banzhuren[50];//班主任姓名
    int boynum;
    int grilnum;//定义结构体类型
};

2.结构体变量类型的声明

1)全局变量

struct class
{
    int number;
    char banzhuren[50];
    int boynum;
    int grilnum;
}one,two;//一班,二班

2)局部变量

struct class one;
struct class two;//该形式也可用于创建全局变量

注意:匿名结构体类型不能定义局部变量。

匿名结构体指:

struct
{
    int number;
    char banzhuren[50];//班主任姓名
    int boynum;
    int grilnum;//定义结构体类型
};

3.结构体变量的初始化

struct class
{
    int number;
    char banzhuren[50];
    int boynum;
    int grilnum;
}one={ 50,"王老师",25,25 },two;//法一
struct class one={ 50,"王老师",25,25 };//法二
struct class one={ .banzhuren="王老师",.boynum=25,.grilnum=25,.number=50 };//法三
//结构成员变量初始化顺序可改变

特殊举例:

struct Stu
{
    char xingbie[20];
    char name[20];
    int xuehao;
}S;
struct class
{
    int number;
    char banzhuren[50];
    int boynum;
    int grilnum;
    struct Stu S;
}one={ 50,"王老师",25,25,{"男","李明”,2},two;//一班,二班

4.结构体变量的打印

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

struct class
{
    int number;
    char banzhuren[50];
    int boynum;
    int grilnum;
}one = { 50,"王老师",25,25 }, two;

int main()
{
    printf("%d %s %d %d", one.number, one.banzhuren, one.boynum, one.grilnum);
return 0;
}

5.结构体内存对齐

结构体的对齐规则:

  1. 第一个成员在与结构体变量偏移量为0的地址处。

2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

VS中默认的值为8

3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整

体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

struct S1 
{
    char c1;//占内存一个字节,偏移量从0开始,偏移1位
    int i;//占内存四个字节,偏移量应是4的倍数,从4开始偏移,偏移4位
    char c2; //占内存一个字节,偏移量应是4的倍数,从8开始偏移,但整体内存应该是4的倍数,所以S1内存为12
};

struct S2
{
    char c1;//占内存一个字节,偏移量从0开始,偏移1位
    char c2;//占内存一个字节,偏移量从1开始,偏移1位
    int i; //占内存四个字节,偏移量应是4的倍数,从4开始偏移,偏移4位,8是4的倍数,所以S2内存是8
};

为什么存在内存偏移?

1.平台原因(移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2. 性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

总体来说:

结构体的内存对齐是拿空间来换取时间的做法。

修改默认对齐数:

//设置默认对齐数
#pragma pack(2)//一般是2的某一次方
//恢复默认对齐数
#pragma pack()

6.结构体传参

struct S
    {
        int data[1000];
        int num;
    };
    
    void print1(struct S s)
    {
        printf("%d %d %d %d\n", s.data[0], s.data[1], s.data[2], s.num);
    }
    
    void print2(const struct S* ps)
    {
        //printf("%d %d %d %d\n", (*ps).data[0], (*ps).data[1], (*ps).data[2], (*ps).num);
        printf("%d %d %d %d\n", ps->data[0], ps->data[1], ps->data[2], ps->num);
    }
    
    int main()
    {
        struct S ss = { {1,2,3,4,5}, 100 };
        print1(ss);//法一
        print2(&ss);//法二,节省空间,更优
    
        return 0;
    }

二.枚举

enum每一个成员都是可能取到的值,是常量,外界不能更改。如果没有赋值,默认第一个常量值是0,第二个值是1,以此类推。

示例:

enum color
{
    red;
    bule;
    yellow;
}

为什么使用枚举?

我们可以使用 #define 定义常量,为什么非要使用枚举?枚举的优点:

1.增加代码的可读性和可维护性-

2.和#define定义的标识符比较枚举有类型检查,更加严谨。

3.防止了命名污染(封装)

4.便于调试

5.使用方便,一次可以定义多个常量

三.联合体(共用体)

共用同一块空间所以叫共用体union,且不能同时用多个共用体的成员。联合体大小至少是最大成员的大小。

示例:

union un
{
char ch;
int i;
double c;
}

如有错误欢迎斧正,如有疑惑可私信或评论,会尽力解答,大家一起加油啊!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值