自定义类型

struct结构体(大小为全部数据类型的和)

结构是一些成员变量的集合,每个成员可以是不同类型的变量

struct tag                 //自定义结构体数据类型(比如int,直接在内存划了一个4个字节的空间
{
    member-list;        //成员列表
}variable-list;           //结构体变量列表

struct Stu
{
 char name[20];//名字
 int age;//年龄
 char sex[5];//性别
 char id[20];//学号
}; //分号不能丢

struct Book
{
    char name[20];//书名
    char author[20]; //作者
    int price;//价格
    char id[15];//书号
}book4, book5;//←这里也是创建结构体变量,在main外面的话是全局变量

struct Book book1 = {"冒险小虎队", "托马斯", 20, "ABC"};//创建struct Book类型 名字为book1
struct Book book2;
struct Book book3;

在声明结构的时候,可以不完全的声明(下面的两个结构在声明的时候省略掉了结构体标签(tag))

//匿名结构体类型
struct
{
 int a;
 char b;
 float c; }x;

struct
{
 int a;
 char b;
 float c; }a[20], *p;

结构体的自引用

struct Node
{
 int data;
 struct Node* next;//指针
};

省略结构体前面的struct(可以的话尽量不省略,免得别人看不懂这是结构体类型)
typedef struct Stu
{
 char name[20];//名字
 int age;//年龄
 char sex[5];//性别
 char id[20];//学号
}Stu; //分号不能丢

结构体内存对齐

#include <stddef.h>

宏,用来计算结构体成员相对于起始位置的偏移量

offsetof(结构体类型名,结构体成员名)

offsetof(struct S1, c1);

第一个成员在与结构体变量偏移量为 0 的地址处
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数(VS 中默认的值为 8) 与 该成员大小的较小值
结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
//练习1
struct S1
{
 char c1;//第一个对其数为1,1和8最小的整数倍为1(0)
 int i;  //第二个对其数为4,4和8最小的整数倍位4(4-7)
 char c2;//第三个对其数为1,1和8最小的整数倍为1(8)
};
printf("%d\n", sizeof(struct S1));//总大小为最大对其数4的倍数,只能是12(0-11)

//练习2
struct S2
{
 char c1;//第一个对其数为1,1和8最小的整数倍为1(0)
 char c2;//第二个对其数为1,1和8最小的整数倍为1(1)
 int i;  //第三个对其数为4,4和8最小的整数倍位4(4-7)
};
printf("%d\n", sizeof(struct S2));//总大小为最大对其数4的倍数,只能是8(0-7)

//练习3
struct S3
{
 double d;//第一个对其数为8,8和8最小的整数倍为8(0-7)
 char c;  //第二个对其数为1,1和8最小的整数倍为1(8)
 int i;   //第三个对其数为4,4和8最小的整数倍位4(12-15)
};
printf("%d\n", sizeof(struct S3));//总大小为最大对其数4的倍数,只能是16(0-15)

//练习4-结构体嵌套问题
struct S4
{
 char c1;//第一个对其数为1,1和8最小的整数倍为1(0)
 struct S3 s3;//第二个对其数为16,16和8最小的整数倍为8(8-23)
 double d;//第三个对其数为8,8和8最小的整数倍为8(24-31)
};
printf("%d\n", sizeof(struct S4));//总大小为最大对其数4的倍数,只能是32(0-31)

结构体节省空间
1.明确结构体成员变量的值域,用适合的类型;

2.根据字节对齐的规则,将成员变量的类型根据从小到大进行声明,尽量减少中间的填补空间;

3.取消字节对齐。#pragma pack(1),自定义默认对齐,一般为2的n次方,设置为1等于取消字节对齐,用时间换空间。

4.根据特定的使用的条件下,可以考虑将结构体换成共用体。

结构体传参(尽量传地址)

#include <stdio.h>

struct S
{
    int data[1000];
    int num;
}

int main()
{
    struct S ss = {{1,2,3,4,5}, 100};
    print(ss);
    print(&ss);
}

void print(struct S s)//传结构体
{
    printf("%d %d %d %d\n",s.data[0],s.data[1],s.data[2],s.num);
}

void print(struct S* ps)//传结构体地址
{
    printf("%d %d %d %d\n",ps→data[0],(*ps).data[1],ps→[2],s.num);//可用箭头,可用小数点
}

结构体位段

位段的成员必须是整型家族int ,unsigned int,或者char

//冒号+数字
struct A
{
    int _a:2(只拿2个比特位)
    int _b:5(只拿5个比特位)
    int _c:10(只拿10个比特位)
    int _d:30(只拿30个比特位)
}

 

结构体柔性数组

c99中,结构中的最后一个元素允许是未知大小的数组,这就叫做【柔性数组】成员

柔性数组成员前面必须至少有一个其他成员。

sizeof()返回的结构体大小不包含柔性数组的内存。

包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构中的大小,以适应柔性数组的预期大小。

struct S
{
    int n;
    float s;
    int *arr;//不是柔性数组
}

int main()
{
    struct S* ps = (struct S*)malloc(sizeof(struct S));//结构体开辟在堆上

    if (ps == NULL)
    {
        return 1;
    }

    int *prt2 = (int*)malloc(sizeof(int)*4);

    if (ptr2 == NULL)
    {
        return 1;
    }
    else
    {
        ps->arr = ptr2;
    }

    //赋值
    ps->n = 100;
    ps->s = 5.5f;
    for(int i = 0; i < 4; i++)
    {
        scanf("%d", &(ps->arr[i]));
    }
    printf("%d %f\n", ps->n, ps->s);
    for(int i = 0; i < 4; i++)
    {
        printf("%d ", ps->arr[i]);
    }
    
    //调整数组大小
    struct S* ptr = (struct S*)relloc(ps->arr, sizeof(int)*10);
    if (ptr == NULL)
    {
        return 1;
    }
    else
    {
        ps->arr = ptr;
    }

    free(ps->arr);//第一次free结构体的一个成员
    ps->arr = NULL;

    free(ps);//第二次free整个结构体
    ps = NULL;
    return 0;
}
struct S
{
    int n;
    float s;
    int arr[];//柔性数组 数组大小未知
    //int arr[0];//柔性数组 数组大小未知
}

int main()
{
    struct S* ps = (struct S*)malloc(sizeof(struct S) + sizeof(int)*4);//8+16

    if (ps == NULL)
    {
        return 1;
    }

    //赋值
    ps->n = 100;
    ps->s = 5.5f;
    for(int i = 0; i < 4; i++)
    {
        scanf("%d", &(ps->arr[i]));
    }
    printf("%d %f\n", ps->n, ps->s);
    for(int i = 0; i < 4; i++)
    {
        printf("%d ", ps->arr[i]);
    }
    
    //调整数组大小
    struct S* ptr = (struct S*)relloc(ps, sizeof(struct S) + sizeof(int)*10);
    if (ptr == NULL)
    {
        return 1;
    }
    else
    {
        ps->arr = ptr;
    }

    free(ps);
    ps = NULL;
    return 0;
}

第二个有两个好处,1为方便内存释放(第一个要释放2次,因为用了两次malloc,他们的空间可能不是连续的),2为有利于访问速度(连续的内存有益于提高访问速度,也有益于减少内存碎片)

枚举enum(大小为1个数据类型的大小,只取其中之一)

枚举括号里的为枚举的可能取值,每一个可能取值都是常量

定义的时候可以赋值,否则从0开始

枚举大小是其中之一的取值大小

enum Day//星期
{
 Mon,    //0
 Tues,   //1
 Wed,    //2
 Thur,   //3
 Fri,    //4
 Sat,    //5
 Sun     //6
};
enum Sex//性别
{
 MALE,   //0
 FEMALE, //1
 SECRET  //2
};
enum Color//颜色
{
 RED,    //0
 GREEN,  //1
 BLUE    //2
};

联合体union(大小为最大数据类型的大小)

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联
合至少得有能力保存最大的那个成员)
#include <stdio.h>

int check_sys();
int main()
{
	if (1 == check_sys())
		printf("小端\n");
	else
		printf("大端\n");
    
	return 0;
}


//利用结构体的储存来判断
int check_sys()
{
	union checksys
	{
		char a;
		int b;
	}cs;

	cs.b = 1;
	return cs.a;
}

联合体大小计算

联合的大小 至少是 最大成员的大小
最大成员大小 不是 最大对齐数 的整数倍的时候,就要对齐到 最大对齐数 的整数倍
union Un1
{
 char c[5];//单个成员大小1,总成员大小5(5是最大成员大小),默认对齐数8,对齐数1
 int i;    //单个成员大小4,总成员大小4,默认对齐数8,对齐数4(4是最大对齐数)
};
//5不是4的倍数,所以4*2,大小是8
union Un2
{
 short c[7];//单个成员大小2,总成员大小14(14是最大成员大小),默认对齐数8,对齐数2
 int i;     //单个成员大小4,总成员大小4,默认对齐数8,对齐数4(4是最大对齐数)
};
//14不是4的倍数,所以大小是16

printf("%d\n", sizeof(union Un1));

printf("%d\n", sizeof(union Un2));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值