您的位置:首页 > 其它

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

2017-11-26 11:47 411 查看

结构体

定义和初始化:

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


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

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 p
4000
rint1(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  struct