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

来源:互联网 发布:js 相对路径 绝对路径 编辑:程序博客网 时间:2024/05/22 10:39

结构体

定义和初始化:

 基本定义:结构体,通俗讲就是打包封装,把一些有共同特性(或属于同一类事物的属性)的变量放在其内部,通过一定方法访问修改内部变量。

结构体的定义方式还有很多种:
1、只有结构体:

struct stu{    char name[20];    int age;    float height;};

2、附加结构体类型的变量的定义:

struct stu{    char name[20];    int age;    float height;}S;

3、简略结构体后面的名字:

struct{    char name[20];    int age;    float height;}S;

4、
添加指针指向结构体变量

struct stu{    char name[20];    int age;}S,*p;

初始化:

struct stu{    char name[20];    int age;}S;struct stu S = { "haha", 18 };

结构体嵌套初始化 :

struct node{    int data;    struct point p;    struct node *next;}n1 = { 10, { 4, 5 },NULL };struct n2 = { 20, {5,6} 18 }; 

结构体的自引用:

这里写图片描述

struct node{    int data;    struct node* next;};

看到这个,是不是想起了数据结构中的链表呢?
这里写图片描述
知道第一个结点,通过指针可以找到后面所有的结点。

结构体的成员:

结构体的成员可以是标量、指针、数组、甚至是其他结构体
那么如何访问其成员呢?
》点操作符

struct stu{    char name[20];    int age;};struct stu s;strcpy(s.name, "haha");s.age = 19;

》指向操作符

struct stu{    char name[20];    int age;}S;void print(struct S* sp){    printf("name=%s age=%d", (*sp->name, *sp.age));}

结构体内存对齐:

1、对齐规则:
i)第一个成员无须偏移(但是他也具有对齐数)。
ii)其他成员变量要对齐到一个数的整数倍处(这个数是对齐数)
vs中默认为8,Linux默认为4
iii)结构体的大小是最大对齐数的整数倍。
iv)嵌套结构体时,嵌套的结构体对齐到自己最大对齐数的整数倍,所以整个结构体的大小就是所有最大对齐数(嵌套的结构体对齐数也在内)的整数倍。
例题:
1、

struct s1{    char c1;    int i;    char c2;};int main(){    printf("%d\n", sizeof(struct s1));    system("pause");    return 0;}

这里写图片描述

2、
这里写图片描述

3、
这里写图片描述

4、结构体嵌套问题
这里写图片描述

这里写图片描述
为什么存在内存对齐?
1、平台原因(移植原因)
不是所有的硬件平台都能访问任意地址上的任意数据;有些平台只能在某些地址处取某些特定类型的数据,否则抛出异常。
2、性能原因
数据结构(尤其是栈)应该尽可能在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器要两次访问;而对齐则只需一次访问。
**总体来说,结构体的内存对齐就是以空间来换时间的做法,所以我们在设计结构体时,要把占用空间小的量尽量放在前面。

结构体传参

结构体传参的时候要传结构体的地址

struct S{    int data[1000];    int num;};struct S s = { { 1, 2, 3, 4 }, 1000 };//void print1(struct S s)//{//  printf("%d\n", s.num);//}void print2(struct S* ps){    printf("%d\n", ps->num);}int main(){    //print1(s);//传结构体    print2(&s);//传地址    system("pause");    return 0;}

上面的两种传参方式,首选传地址,这就和我们函数传参形成栈帧有关了,如果直接传一个结构体对象,假如结构体很大,那么压栈开销就会很大,导致性能的下降,在这个例子中,他结构体中还有数组,所以传结构体对象时数组不会传过去,而是会一遍遍实例化数组,所以开销是非常大的。

结构体实现位段:

位段的声明和结构体类似,1、位段的成员必须是int、unsigned int、或者signed int。2、位段的成员名后面有一个冒号和一个数字。比如:

struct A{    int _a : 2;    int _b : 5;    int _c : 10;    int _d : 30;};

这里写图片描述
所以A需要两个int,大小就是8字节
再例如:
这里写图片描述

位段的内存分配:

1、位段的成员必须是位段的成员必须是int、unsigned int、或者signed int或者char(整型家族)2、位段的空间是按照4字节(int)或者1字节(char)的方式来开辟的。3、位段涉及很多不确定因素,不跨平台

不跨平台的原因:
int 是有符号还是无符号是不确定的。
位段中最大位的数目不确定。(16位机器是16,32位机器是32)。
位段中成员在内存中从左向右分配,还是从右向左不确定
当一个结构有两个位段,第二个位段成员比较大,无法容纳第一个位段剩的位时,是舍弃剩余的位还是利用,也是不确定的。

枚举

一 一列举。

定义:

enum day{    sun,    mon,    tues,    wed,    thur,    fri,    sat,};

定义一个周从星期天到星期六是枚举。{}中的内容是枚举类型的可能取值,也叫枚举常量,这些取值都是有值的,默认从零开始,每次递增一

使用:

只能用枚举常量给枚举变量赋值:

enum day{    sun,    mon,    tues,    wed,    thur,    fri,    sat,};enum day d = sun;d = 0;

优点:

 1、增加代码可读性和可维护性。 2、与define定义的宏相比他有类型检查。 3、防止明名污染(封装)。 4、便与调试。 5、使用方便,一次可定义多个常量。

联合(共用体)

定义:

联合定义的变量包含一系列的成员,特征是这些成员共用同一块空间。

使用:

联合的成员是共用一块空间的,所以一个联合变量的大小,至少是最大成员的大小(因为联合至少有能力保存最大的那个成员)。
下面的代码输出结果相同,可以看出,成员确实共用一块空间。

union Un{    int i;    char c;};int mian(){    union Un un;    printf("%d\n", &(un.i));    printf("%d\n", &(un.c));    printf("%d\n", &(un));    system("pause");    return 0;}

应用:
判断计算机的大小端存储:

#include<stdio.h>union Un{    int i;    char c;};int mian(){    union Un un;    un.i = 0x11223344;    un.c = 0x55;    printf("%x", un.i);    system("pause");    return 0;}

输出结果为:0x11223355由于我的计算机是小端存储,而c占i4个字节的低位,低地址放在低位就是小端存储。

计算联合变量的大小:
联合的对齐:
~联合的大小至少是最大成员的大小。
~当最大成员不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍。

#include<stdio.h>union Un1{    int i;    char c[5];};union Un2{    short c[7];    int i;};int mian(){    printf("%d\n",sizeof(union Un1));//8    printf("%d\n", sizeof(union Un2));//16    system("pause");    return 0;}
阅读全文
0 0
原创粉丝点击