博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自定义类型
阅读量:4117 次
发布时间:2019-05-25

本文共 4486 字,大约阅读时间需要 14 分钟。



【结构体】

     结构体是将具有不同或者相同元素类型放在一起的聚合类型。

一,结构体类型的声明

struct tag//struct是关键字,tag是标签,要见名知意。这里tag可省略,但不建议省略。{member_list;//声明一种类型,在c语言中,这里不能为空。}variable_list;//结构体变量列表,变量可以有多个。这里建议省略,需要用的时候再定义。

注意{};,后面的分号不能丢。

看下面一个声明:

struct A{	int a;	char b;	float c;}a[20],*p;struct B{	int a;	char b;	float c;}x;p = &x;

结果有报错:

编译器会把上面两个声明当成两个完全不同的两个类型,所以是非法的。

二,结构体成员

 结构体成员可以是标量,数组,指针,也可以是其他结构体。

那么结构体是怎样访问成员呢?

结构体变量的成员是通过点操作符(.)或者—>访问的.

举个例子:

#include
#include
struct Test{ int a; char b; float c;};int main(){ struct Test A; struct Test *p; A.a = 10;//使用.访问a成员 A.b = 'B';//使用.访问b成员 p = &A; (*p).a = 20; (*p).b = 'b'; printf("a=%d b=%c", (*p).a, (*p).b); printf("\n"); printf("a=%d b=%c", p->a, p->b); system("pause"); return 0;}

最后结果是

三.结构体的自引用:

在结构体中包含一个类型为该结构体本身的成员可以吗?

先来试一试:

struct Node{	int data;	struct Node next;};

编译显示

编译显示“next”没有被定义,可见直接在结构体中定义一个该结构体本身的变量是不合法的,正确的定义应该如下:

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

四,结构体的不完整声明

在结构体套结构体使用时,在不声明的情况下,两个相互套用,虽然在vs2013下能够通过运行,但是最好还是提前声明。

struct B;struct A{	int _a;	struct B* pb;};struct B{	int _b;	struct A* pa;};

五,结构体变量的定义和初始化(类比数组)

//声明:struct Test{	int a;	char b;};//定义:struct Test p1;struct Test p2;//初始化://p1 = {a,b}//这种初整体始化的方式是不允许的,类比数组;struct Test p1 = {20,'a'};

struct Node{	int d[10];	struct Test;	struct Node *next; };struct Node n = { { 1, 2, 3 }, { 20, 'a' }, NULL };//结构体嵌套初始化

六,结构体内存对齐

前面了解了结构体的概念,那么结构体的大小如何计算呢?它是是不是也可以类比数组呢?经过验证我们发现,当结构体内声明的类型顺序不一样时,结构体的大小也不一样。所以,计算结构体大小不能类比数组,这里还需要考虑内存对齐问题。

1.为什么存在内存对齐呢?

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

(2)、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

2.结构体的内存对齐规则:

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

【2】.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
    VS中默认的值为8
    linux中的默认值为4
【3】.结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍。
【4】.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

现在来看一个例子:

struct S1{	char c1;	int i;	char c2;};

结构体s1里的char c1的对齐数是1,第一个成员默认偏移量为0;int i的对齐数是4,1不能整除自身对齐数,所以得加上偏移量3;char c2的对齐数是1,8能够整除自身对齐数,就不需要加偏移量;最后看结构体总的大小为9,不能整除结构体中最大对齐数4,所以加偏移量3,最后结构体大小为12.

用图形理解如下:

结构体嵌套问题:

struct S1{	char c1;//1+3	int i;//4+4	char c2;//8+1};//12struct S2{	int a[5];//20	struct S1 s1;//12+20	double d;//8};//40

结构体s2里,int a[5]的对齐数为20;然后嵌套了结构体S1,嵌套的结构体对齐到自己的最大对齐数的整数倍处,这里20能够整除最大对齐数4,所以不需要偏移量;double d 对齐数是8,32能够整除8,;结构体总大小为40,能够整除最大对齐数8;最后S2的大小为40.

七,结构体传参

   结构体传参传指针。

#include
#include
struct S{ int date[1000]; int num;};void print(struct S *s){ printf("%d\n", s->num);//20}int main(){ struct S s = { { 1, 2, 3, 4 }, 20 }; print(&s); system("pause"); return 0;}

【枚举】

一,枚举的定义

//一般的定义方式如下:enum enum_type_name{ENUM_CONST_1,ENUM_CONST_2,...ENUM_CONST_n} enum_variable_name;

注意:enum_type_name是自定义的一种数据数据类型名,而enum_variable_name为

enum_type_name类型的一个变量,也就是我们平时常说的枚举变量。实际上enum_type_name
类型是对一个变量取值范围的限定,而花括号内是它的取值范围,即enum_type_name类型
的变量enum_variable_name只能取值为花括号内的任何一个值,如果赋给该类型变量的值
不在列表中,则会报错或者警告。ENUM_CONST_1、ENUM_CONST_2、...、
ENUM_CONST_n,这些成员都是常量,也就是我们平时所说的枚举常量(常量一般用大写)。

                                                                                           ------------------- ---摘录《c语言深度解剖》

二,枚举的初始化

enum Color{	RED,	BIACK,	BLUE,}; int main(){	enum color c;	c = BLUE;	printf("%d\n", RED);//0	system("pause");	return 0;}

{}里的内容是枚举类型的可取值,也叫枚举常量,这些可取值都是有值的,默认从0开始,一次递增1.

在定义的时候也可以赋值(枚举常量)。

三,下面再看看枚举与#define宏的区别:

1),#define宏常量是在预编译阶段进行简单替换。枚举常量则是在编译的时候确定其值。

2),一般在编译器里,可以调试枚举常量,但是不能调试宏常量。
3),枚举可以一次定义大量相关的常量,而#define宏一次只能定义一个。

【联合体】

一,联合体类型的声明,定义与初始化

//声明union Un{	int a;	float b;	char c;};int main(){	union Un x;//定义	x.a = 25;	printf("%d\n", x.a );	x.b=3.14;	printf("%lf\n", x.b); //3.140000	x.c = 'c';	printf("%c\n", x.c);	system("pause");	return 0;}

二,联合的特点

            在union中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址。这样一个联合变量的大小,至少是最大成员的大小。

看一个例子:

union Un{	int i;	char c;};int main(){	union Un un;		printf("%d\n", &(un.i)); 	printf("%d\n", &(un.c)); 	un.i = 0x11223344;	un.c = 0x55;	printf("%x\n", un.i); //11223355	system("pause");	return 0;}

编译后,我们发现,结构体成员的地址都是相同的.

现在看看内存:

对union型的成员的存取都是相对于该联合体基地址的偏移量为0处开始,也就是联合体的访问不论对哪个变量的存取都

是从union的首地址位置开始。然后根据大端小端判断,计算机是小端模式,所以结果是0x11223355。

【判断当前计算机的大小端存储】

int check_sys(){	int i = 1;//0000  0000 0000 0000 0000 0000 00001	return (*(char *)&i);//对&i解引用就是首地址;}int main(){	int ret = check_sys();	if (ret == 1)	{		printf("xiaoduan\n");	}	else	{		printf("daduan\n");	}	system("pause");	return 0;}

看内存,低位保存在低地址中,编译后结果也是小端。

三,联合体大小是计算

union Un{	char c[5];//5	int i;//4};int main(){		printf("%d\n",sizeof(union Un));//8		system("pause");	return 0;}

联合体大小至少是最大成员的大小;当最大成员不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍。

你可能感兴趣的文章
数据库
查看>>
nginx反代 499 502 bad gateway 和timeout
查看>>
linux虚拟机安装tar.gz版jdk步骤详解
查看>>
python猜拳游戏
查看>>
python实现100以内自然数之和,偶数之和
查看>>
python数字逆序输出及多个print输出在同一行
查看>>
ESP8266 WIFI数传 Pixhaw折腾笔记
查看>>
苏宁产品经理面经
查看>>
百度产品经理群面
查看>>
去哪儿一面+平安科技二面+hr面+贝贝一面+二面产品面经
查看>>
element ui 弹窗在IE11中关闭时闪现问题修复
查看>>
vue 遍历对象并动态绑定在下拉列表中
查看>>
Vue动态生成el-checkbox点击无法选中的解决方法
查看>>
python __future__
查看>>
MySQL Tricks1
查看>>
python 变量作用域问题(经典坑)
查看>>
pytorch
查看>>
pytorch(二)
查看>>
pytorch(三)
查看>>
pytorch(四)
查看>>