脚本宝典收集整理的这篇文章主要介绍了自定义类型:结构体,枚举,联合(C语言),脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
在C语言中有一些内置的类型:整型(int long short……),当然也有自定义类型,这次我们介绍关于常见的自定义类型(结构体、枚举、联合)。
结构体我们在前面简单介绍过,是用来描述复杂对象的,比如:人,我们在描述人时,不能仅仅通过整型或者浮点型来描述所谓的人,我们需要通过一系列的类型来描述人这个复杂对象,比如:年龄,身高,体重,地址,电话等等,因此我们需要自己创建一个类型,这个类型就是结构体。
我们如何申明结构体呢?
struct tag
{
member-list;
}VARiable-list;
struct是结构体关键字,tag是标签名,;member-list是成员列表,variable-list是变量列表。我们来看例子:
struct Book
{
char name[20];
char author[20];
int PRice;
}B1;
我们创建了一个Book的结构体,结构体中有name[20],author[20],price三个成员,B1就是一个创建的变量。
什么是结构体的自引用?自己类型的对象,要找到自己内部同一个类型的另一个对象,就叫自引用。在数据结构中我们会学到链表,链表的节点就是采用的结构体的自引用。
struct Node
{
int date;
struct Node* next;
};
节点会分为两个区域,数据域和指针域,数据域是用来存放数据的,指针域用来存放地址。date就是存放数据,next就是存放指针,而指针的类型就是struct Node这个类型。
结构体变量的定义和初始化相对来说就比较的简单:
struct Point
{
int x;
int y;
}P3 = { 5,6 }, p4 = {7,8};
struct Point p2 = {1,2};
int main()
{
struct Point p1 = {3,4};
return 0;
}
我们创建了4个变量:p1,p2,p3,p4,这4个变量都是struct Point类型的,区别就在于p1是局部变量,而p2,p3,p4是全局变量。
我们先看一个题目:
#include<stdio.h>
struct S1
{
char c1;
int a;
char c2;
};
struct S2
{
char c1;
char c2;
int a;
};
int main()
{
printf("%dn", sizeof(struct S1));
printf("%dn", sizeof(struct S2));
return 0;
}
打印结果是什么呢? 有同学会说,char是一个字节,int是两个字节,s1和s2就是int前后位置发生了变化,所以打印结果都是6。那么真的是这样嘛?
我们看到打印结果都不是6,为什么呢?这就涉及到了结构体内存对齐的知识。 我们先介绍关于结构体内存对齐的规则:我们先看一个例子:
#include<stdio.h>
struct S
{
int data[1000];
int num;
};
void print1(struct S tmp)
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", tmp.data[i]);
}
printf("nnum=%dn", tmp.num);
}
int main()
{
struct S s = { {1,2,3,4,5,6,7,8,9,10},100 };
print1(s);
return 0;
}
我们利用print1()函数打印了s的信息,我们可以看到,我们是将s的值传给了tmp,也就是说我们又重新创建了一个struct S类型的结构体,然后打印重新创建结构体的内容,这样就会导致空间的浪费,那么还有什么方法呢?
#include<stdio.h>
struct S
{
int data[1000];
int num;
};
void print2(struct S *ps)
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", ps->data[i]);
}
printf("nnum=%dn", ps->num);
}
int main()
{
struct S s = { {1,2,3,4,5,6,7,8,9,10},100 };
print2(&s);
return 0;
}
print2()函数采用的是传结构体的地址,这样就只需要创建一个地址空间来存放目标的地址,然后在打印结构,效率就会远大于print1()函数,其实有点类似于传值和传址。所以在遇到结构体时一般采用传址操作,因为结构体包含很多类型,往往空间会比较大。
什么是位段?
我们来看一个例子:
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
这就是一个位段,那么位段是干什么用的呢?位段的作用其实就是用来节省空间的,“2”是分配给"_a"2个bIT位,同理"5"是5个bit位,那么具体是如何分配的呢?以struct A为例:当我们创建时,编译器先看到int _a,那么开辟4个字节(32个bit位),_a需要2个,_b需要5个,_c需要10个,此时还剩15个bit位,无法分配给_d,因此在开辟4个字节,给_d使用因此,此时struct A的总大小位8个字节。 通过例子总结出位段的内存分配:
位段是不具备跨平台的。
枚举顾名思义就是一一列举。把可能的取值一一列举。比如我们现实生活中:一周的星期一到星期日是有限的7天,可以一一列举。性别有:男、女、保密,也可以一一列举。月份有12个月,也可以一一列举颜色也可以一一列举。这里就可以使用枚举了。一般枚举是枚举有限多个,无限多个就不会采用枚举了
我们看例子:
enum Day
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex
{
MALE,
FEMALE,
SECRET
};
enum Color
{
red,
GREEN,
BLUE
};
以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。 {}中的内容是枚举类型的可能取值,也叫 枚举常量 。这些可能取值都是有值的,默认从0开始,一次递增1。当然也可以自定义枚举常量的数值。
enum Color
{
RED=1,
GREEN=2,
BLUE=4
};
我们在前面常量中学过使用#define可以定义常量,那么为什么还要有枚举常量呢? 枚举的优点:
enum Color
{
RED,
GREEN,
BLUE
};
int main()
{
enum Color c = GREEN;
if (c == GREEN)
{
printf("绿色n");
}
return 0;
}
枚举的使用就是利用枚举的常属性进行逻辑的运算,当然这只是一方面。通过枚举的使用可以使代码的可读性提高,维护起来也相对方便。
联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。
我们看例子:
union Un
{
char c;
int i;
};
这就是联合体的定义,我们可以看到联合体跟结构体很像但是,在内存分配上是不一样的。这就是联合体的特点。
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。什么意思呢?我们拿上面的例子举例:
#include<stdio.h>
union Un
{
char c;
int i;
};
int main()
{
union Un u = { 0 };
printf("%dn", sizeof(u));
printf("%pn", &u);
printf("%pn", &(u.c));
printf("%pn", &(u.i));
return 0;
}
通过打印我们可以看到,联合体大小为4,并且每个成员的地址都是联合体的地址,这就意味着每个成员是共用内存的。 所以当c和i相互制约,当两者其中改变时(c所在的内存发生改变),会影响到另一个。
比如:
#include<stdio.h>
union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};
int main()
{
printf("%dn", sizeof(union Un1));
printf("%dn", sizeof(union Un2));
return 0;
}
我们看Un1,char c[5]占5个字节,int i占4个字节,所以Un1为5个字节,但是第一个是char类型,对齐数是1;第二个是int,对齐数是4,最大对齐数是4,所以Un1大小应为4的倍数,所以Un1大小为8。同理Un2,short c[7]占14个字节,int i占4个字节,所以Un2为14个字节,但是short对齐数为2,int对齐数为4,所以Un2应为4的倍数,所以Un2为16。
以上是脚本宝典为你收集整理的自定义类型:结构体,枚举,联合(C语言)全部内容,希望文章能够帮你解决自定义类型:结构体,枚举,联合(C语言)所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。