B 添加义项
?
“结构”是一种构造类型,它是由若干“成员”组成的。 每一个成员可以是一个基本数据类型或者又是一个构造类型。 结构即是一种“构造”而成的数据类型, 那么在说明和使用之前必须先定义它,也就是构造它。如同在说明和调用函数之前要先定义一样。
10
本词条 正文缺少必要目录和内容, 欢迎各位 编辑词条,额外获取10个积分。
基本信息
中文名称
结构体
外文名称
struct
组成
若干成员”
类型
构造类型
目录1结构类型2结构定义 3结构说明4对齐方式
结构类型折叠编辑本段
在实际问题中,一组数据往往具有不同的数据类型。例如, 在学生登记表中,姓名应为字符型;学号可为整型或字符型; 年龄应为整型;性别应为字符型;成绩可为整型或实型。 显然不能用一个数组来存放这一组数据。 因为数组中各元素的类型和长度都必须一致,以便于编译系统处理。为了解决这个问题,C语言中给出了另一种构造数据类型——“结构”。 它相当于其它高级语言中的记录。
“结构”是一种构造类型,它是由若干“成员”组成的。 每一个成员可以是一个基本数据类型或者又是一个构造类型。 结构即是一种“构造”而成的数据类型, 那么在说明和使用之前必须先定义它,也就是构造它。如同在说明和调用函数之前要先定义一样。
结构定义折叠编辑本段
定义一个结构的一般形式为:
struct 结构名
{
成员表列
}
成员表由若干个成员组成, 每个成员都是该结构的一个组成部分。对每个成员也必须作类型说明,其形式为:
类型说明符 成员名
成员名的命名应符合标识符的书写规定。
例如:
struct stu
{
int num
char name[20]
char sex
float score
}
在这个结构定义中,结构名为stu,该结构由4个成员组成。 第一个成员为num,整型变量;第二个成员为name,字符型数组;第三个成员为sex,字符型变量;第四个成员为score,浮点型变量。 应注意在括号后的分号是必不可少的。
值得一提的是,在C++中,struct的功能得到了强化,struct不仅可以添加成员变量,还可以添加成员函数,和class类似
结构说明折叠编辑本段
结构定义之后,即可进行变量说明。 凡说明为结构stu的变量都由上述4个成员组成。由此可见, 结构是一种复杂的数据类型,是数目固定,类型不同的若干有序变量的集合。
请看下面的结构:
struct MyStruct
{
double dda1
char dda
int type
}
对结构MyStruct采用sizeof会出现什么结果呢?sizeof(MyStruct)为多少呢?也许你会这样求:
sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13
但是当在VC中测试上面结构的大小时,你会发现sizeof(MyStruct)为16。你知道为什么在VC中会得出这样一个结果吗?
其实,这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式(vc6.0,32位系统)。
类型
对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
Char
偏移量必须为sizeof(char)即1的倍数
int
偏移量必须为sizeof(int)即4的倍数
float
偏移量必须为sizeof(float)即4的倍数
double
偏移量必须为sizeof(double)即8的倍数
Short
偏移量必须为sizeof(short)即2的倍数
对齐方式折叠编辑本段
默认的对齐方式
各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节VC会自动填充。同时VC为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
下面用前面的例子来说明VC到底怎么样来存放结构的。
struct MyStruct
{
double dda1
char dda
int type
}
为上面的结构分配空间的时候,VC根据成员变量出现的顺序和对齐方式,先为第一个成员dda1分配空间,其起始地址跟结构的起始地址相同(刚好偏移量0刚好为sizeof(double)的倍数),该成员变量占用sizeof(double)=8个字节;接下来为第二个成员dda分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为8,是sizeof(char)的倍数,所以把dda存放在偏移量为8的地方满足对齐方式,该成员变量占用sizeof(char)=1个字节;接下来为第三个成员type分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为9,不是sizeof(int)=4的倍数,为了满足对齐方式对偏移量的约束问题,VC自动填充3个字节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为12,刚好是sizeof(int)=4的倍数,所以把type存放在偏移量为12的地方,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:8+1+3+4=16,刚好为结构的字节边界数(即结构中占用最大空间的类型所占用的字节数sizeof(double)=8)的倍数,所以没有空缺的字节需要填充。所以整个结构的大小为:sizeof(MyStruct)=8+1+3+4=16,其中有3个字节是VC自动填充的,没有放任何有意义的东西。
下面再举个例子,交换一下上面的MyStruct的成员变量的位置,使它变成下面的情况:
struct MyStruct
{
char dda
double dda1
int type
}
这个结构占用的空间为多大呢?在VC6.0环境下,可以得到sizeof(MyStruct)为24。结合上面提到的分配空间的一些原则,分析下VC怎么样为上面的结构分配空间的。(简单说明)
struct MyStruct
{
char dda//偏移量为0,满足对齐方式,dda占用1个字节;
double dda1//下一个可用的地址的偏移量为1,不是sizeof(double)=8
//的倍数,需要补足7个字节才能使偏移量变为8(满足对齐
//方式),因此VC自动填充7个字节,dda1存放在偏移量为8
//的地址上,它占用8个字节。
int type//下一个可用的地址的偏移量为16,是sizeof(int)=4的倍
//数,满足int的对齐方式,所以不需要VC自动填充,type存
//放在偏移量为16的地址上,它占用4个字节。
}//所有成员变量都分配了空间,空间总的大小为1+7+8+4=20,不是结构
//的节边界数(即结构中占用最大空间的类型所占用的字节数sizeof
//(double)=8)的倍数,所以需要填充4个字节,以满足结构的大小为
//sizeof(double)=8的倍数。
所以该结构总的大小为:sizeof(MyStruct)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的,没有放任何有意义的东西。
字节的对齐方式
VC对结构的存储的特殊处理确实提高了CPU存储变量的速度,但有时也会带来一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。
VC中提供了#pragmapack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;
否则必须为n的倍数。下面举例说明其用法。
#pragmapack(push) //保存对齐状态
#pragmapack(4)//设定为4字节对齐
struct test
{
char m1
double m4
int m3
}
#pragmapack(pop)//恢复对齐状态
以上结构的大小为16,下面分析其存储情况,首先为m1分配空间,其偏移量为0,满足我们自己设定的对齐方式(4字节对齐),m1占用1个字节。接着开始为m4分配空间,这时其偏移量为1,需要补足3个字节,这样使偏移量满足为n=4的倍数(因为sizeof(double)大于n),m4占用8个字节。接着为m3分配空间,这时其偏移量为12,满足为4的倍数,m3占用4个字节。这时已经为所有成员变量分配了空间,共分配了16个字节,满足为n的倍数。如果把上面的#pragmapack(4)改为#pragma pack(16),那么我们可以得到结构的大小为24。
# include<stdio.h># include<string.h>
struct tongxun
{char name[20]
char number[20]
struct tongxun *next
}
int all=0
struct tongxun* tj() /*创建链表并添加成员*//**/
{
struct tongxun *head=NULL
struct tongxun *p,*q
system("CLS")
p=q=(struct tongxun *)malloc(sizeof(struct tongxun))
for()
{printf("请输入姓名:(如果输入0则退出添加)\n")
scanf("%s",p->name)
if(!(strcmp(p->name,"0"))){ free(p)return head}
else {printf("请输入电话号码:\n")
scanf("%s",p->number)
all++
if(all==1)
{p->next=head
q=p
head=q}
else
{p->next=NULL
q->next=p
q=p
}
p=(struct tongxun *)malloc(sizeof(struct tongxun))
}
}
}
cz(struct tongxun *head) /*查找函数*/
{char name1[20],*a
struct tongxun *p
p=heada=name1
system("CLS")
printf("请输入要查找的姓名:\n")
scanf("%s",a)
while(p!=NULL)
{if((strcmp(p->name,a))==0) {printf("姓名:%s\n电话号码:%s\n",p->name,p->number)return}
else p=p->next
}
printf("没有此人\n")
return
}
insert(struct tongxun *head) /*插入新成员*/
{struct tongxun* pnew
pnew=(struct tongxun *)malloc(sizeof(struct tongxun))
while(1)
{printf("请输入姓名:(如果输入0则退出添加)\n")
scanf("%s",pnew->name)
if(!(strcmp(pnew->name,"0"))){ free(pnew)return head}
else {printf("请输入电话号码:\n")
scanf("%s",pnew->number)
all++
pnew->next=head
head=pnew
pnew=(struct tongxun *)malloc(sizeof(struct tongxun))
}
}
}
shuchu(struct tongxun *head)/*输出成员*/
{struct tongxun *p
p=head
printf("这里一共有%d个成员\n",all)
while(p!=NULL)
{printf("姓名:%s\n电话号码:%s\n",p->name,p->number)
p=p->next
}
}
xg(struct tongxun *head) /*修改成员*/
{char name1[20],*a
struct tongxun *p
p=heada=name1
system("CLS")
printf("请输入要修改的姓名:\n")
scanf("%s",a)
while(p!=NULL)
{if((strcmp(p->name,a))==0) {printf("请重新输入姓名:\n")
scanf("%s",p->name)
printf("请重新输入电话号码:\n")
scanf("%s",p->number)return}
else p=p->next
}
printf("没有此人\n")
return
}
sc(struct tongxun *head) /*删除成员*/
{char name1[20],*a
struct tongxun *p,*q
p=q=heada=name1
system("CLS")
printf("请输入要删除的姓名:\n")
scanf("%s",a)
while(p!=NULL)
{
if((strcmp(p->name,a))==0) {all--q->next=p->nextreturn}
else {q=pp=p->next}
}
printf("没有此人\n")
return
}
void main()
{struct tongxun *headint i
while(1)
{printf("请选择:\n")
printf("1.添加 2.查找 3.修改 4.删除5.插入 6.输出\n")scanf("%d",&i)
switch(i)
{case 1:head=tj()break
case 2:cz(head)break
case 3:xg(head)break
case 4:sc(head)break
case 5:insert(head)break
case 6:shuchu(head)break
default:printf("输入有误,请重新输入:\n")break
}
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)