C语言:自定义类型

个人博客网址:https://ljsblog.com

自定义类型(九)

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

结构体

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
结构体成员可以是标量,数组,指针,其他结构体。

结构的声明

形式1

struct 结构体名
{
    成员列表;
};

//例如描述一个学生
#include <stdio.h>
struct Stu
{
    //定义一个结构体类型
    char name[20];//姓名
    short age;//年龄
    char sex[5];//性别
}s1,s2,s3;//创建了三个全局的结构体变量:s1,s2,s3
int main()
{
    struct Stu s;//创建局部结构体变量
    return 0;    
}

形式2

typedef struct 结构体名
{
    成员列表;
}结构体别名;
//例如描述一个学生
#include <stdio.h>
typedef struct Stu
{
    //定义一个结构体类型
    char name[20];//姓名
    short age;//年龄
    char sex[5];//性别
}Stu;
int main()
{
    Stu s1;//等同于struct Stu s1;
    return 0;
}

特殊的声明(不建议用)

//匿名结构体类型
struct
{
    char name[20];
    short age;
    char sex[5];
}s;//匿名结构体类型只能在这里创建变量

结构体的自引用

//错误实例
struct S
{
    int num;
    struct S next;//死递归
};

//正确实例
struct S
{
    int num;
    struct S* next;
};

结构体变量的定义和初始化

#include <stdio.h>
struct A
{
    int a;
    char s[20];    
};
struct B
{
    char c[20];
    struct A a1;
    int d;
};
int main()
{
    struct B b1={"hello",{30,"hello world"},50};//初始化
    //访问结构体成员:
    //结构体变量.结构体成员
    printf("%s\n",b1.c);
    printf("%d\n",b1.a1.a);
    printf("%s\n",b1.a1.s);
    printf("%d\n",b1.d);
    return 0;
}
/*
hello
30
hello world
50
*/

结构体成员的访问

  1. 结构体变量.结构体成员
  2. 结构体指针->成员名
#include <stdio.h>
typedef struct Stu
{
    char name[20];
    int age;
    char sex[5];
}Stu;
void print1(Stu s)
{
    printf("%s\n",s.name);
    printf("%d\n",s.age);
    printf("%s\n",s.sex);
}
void print2(Stu* p)
{
    printf("%s\n",p->name);
    printf("%d\n",p->age);
    printf("%s\n",p->sex);
}
int main()
{
    Stu s1={"张三",20,"男"};//初始化
    print1(s1);
    print2(&s1);
	return 0;
}
/*打印结果
张三
20
男
张三
20
男
*/
//以上print1和print2两个函数尽量用print2
//传值时,相当于拷贝了一份结构体过去,传址时,是拷贝了一份地址,所以传址性能更高
//所以结构体传参时,尽量选择传结构体的地址

结构体内存对齐

对齐数就是编译器默认的对齐数与该成员大小的较小值。
vs默认对齐数为8。
gcc没有默认对齐数,直接将成员大小作为对齐数。
对齐规则

  • 结构体第一个成员在与结构体变量偏移量为0的地址处。
  • 其他成员要对齐到对齐数的整数倍的地址处。
  • 结构体总大小为最大对齐数的整数倍。
  • 嵌套结构体对齐到自己的最大对齐数的整数倍处,结构体的大小就是最大对齐数(含嵌套结构体的对齐数)的整数倍

例:

#include <stdio.h>
struct A
{
    double d;//double类型大小为8,vs默认对齐数为8,所以对齐数8
    char a;//char类型大小为1,vs默认对齐数为8,所以对齐数1
    int i;//int类型大小为4,vs默认对齐数为8,所以对齐数4
};
int main()
{
    printf("%d\n",sizeof(struct A));//16
    return 0;
}
#include <stdio.h>
struct A
{
    int n;//4/8 4
    char ch;//1/8 1
    int t;//4/8 4
};
struct B
{
    double d;//8/8 8
    char a;//1/8 1
    int i;//4/8 4
    struct A a1;//4/8 4
};
int main()
{
    printf("%d\n",sizeof(struct B));//32
    return 0;
}

:为节省空间,在创建结构体时,尽量让占用空间小的成员集中在一起。

#pragma pack()

当结构在对齐方式不合适时,可以更改默认对齐数

//#pragma pack()用来修改默认对齐数
#include <stdio.h>
struct A
{
    double d;
    char c;
};
int main()
{
    printf("%d\n",sizeof(struct A));//16
    return 0;
}

修改默认对齐数后

#include <stdio.h>
#pragma pack(2)//设置默认对齐数为2,一般设的对齐数是2,4,8,16这样的数字
struct A
{
    double d;
    char c;
};
#pragma pack()//恢复到原来默认的对齐数
int main()
{
    printf("%d\n",sizeof(struct A));//10
    return 0;
}

C库宏:offsetof()

offsetof()可以给出一个结构成员相对于结构开头的字节偏移量。
头文件:stddef.h
offsetof(结构体名字, 成员名字)
例:

#include <stdio.h>
#include <stddef.h>
struct A
{
    double d;
    char c;
};
int main()
{
    printf("%d\n",offsetof(struct A,d));//0
    printf("%d\n",offsetof(struct A,c));//8
    return 0;
}

位段

位段的声明和结构体类似,但有两点不同:

  1. 位段的成员必须是int,unsigned int,signed int或者char。
  2. 位段的成员名后边有一个冒号和一个数字,数字代表多少二进制位。

内存分配

  1. 位段的成员可以是int,unsigned int,signed int或者char。
  2. 位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。
  3. 位段不具有跨平台性,注意可移植的程序应该避免使用位段。

例:

#include <stdio.h>
struct A
{
    int a:5;
    int b:10;
    int c:15;
    int d:20;
};
struct B
{
    char a:2;
    char b:4;
    char c:5;
    char d:7;
};
int main()
{
    printf("%d\n",sizeof(struct A));//8
    printf("%d\n",sizeof(struct B));//3
    return 0;
}

:与结构体相比,位段可以很好的节省空间,但有跨平台的问题存在

枚举

枚举就是一一列举。

定义格式

enum 枚举名
{
    枚举成员1,
    枚举成员2,
    ……
};

第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。
也可以在定义枚举类型时改变枚举元素的值。
例:

#include <stdio.h>
enum Sex
{
    MALE,//0
    FEMALE,//1
    SECRET//2
};
enum color
{
   BLUE,//0
   RED=3,//3
   GREEN //4
};
int main()
{
    printf("%d %d %d\n",MALE,FEMALE,SECRET);//0 1 2
    printf("%d %d %d\n",BLUE,RED,GREEN);//0 3 4
    return 0;
}

联合(共用体)

联合是一种特殊的自定义数据类型,联合定义的变量包含一系列的成员,这些成员公用同一块空间,任何时候只能有一个成员带有值。

定义

union 联合名
{
   成员列表;

};

例:

//判断大端小端
#include <stdio.h>
int check()
{
    union un
    {
        int i;
        char c;
    }u1;
    u1.i=1;
    return u1.c;
}
int main()
{
    int ret=check();
    if(ret==1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}

联合体的大小

  • 联合的大小至少是最大成员的大小
  • 当最大成员的大小不是最大对齐数的整数倍时,对齐到最大对齐数的整数倍

例:

#include <stdio.h>
union un
{
    int a;//大小为4,对齐数为:4/8 4
    char s[7];//数组的对齐数看数组元素
    //大小为7,对齐数为:1/8 1
};
int main()
{
    printf("%d\n",sizeof(union un));//8
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值