数据结构 -- 结构体Struct

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 -- 结构体Struct相关的知识,希望对你有一定的参考价值。

参考技术A

在 C 语言中,可以使用结构体( Struct )来存放一组不同类型的数据。结构体是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称为结构体的成员( Member )。结构体的定义形式为:

结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间。结构体变量才包含了实实在在的数据,需要内存空间来存储。

stu 为结构体名,里面包含name、num、age、group、score这5个成员。 stu1 和 stu2 则为两个stu类型的结构体变量。

直接将变量放在结构体的最后即可。

如上所示,在 stu 结构体里还定义了『结构体变量sub1』和『结构体sub2』,由于 sub2 没有定义变量,所以其内部成员 score 即为母结构体stu的成员变量。

使用点号 . 获取结构体变量的单个成员,然后再进行赋值操作。

也可以在定义结构体变量时整体赋值:

结构体中各成员在内存中是按顺序依次存储的,成员之间不互相影响,各占用不同的内存空间。结构体变量占用的内存大于等于所有成员占用的内存的总和,因为成员在存储时需要遵循结构体的内存对齐规则,成员之间可能会存在裂缝。

先来看看结构体的内存对齐规则:

看完内存对齐规则是不是感觉有点绕?不急,接下来通过分析具体例子来理解这个规则。

示例1:含有多种数据类型成员

输出结果分析:

根据上面的分析可知,struct1的成员总共需要18字节内存,根据规则3,struct1的内存大小必须是8(double a)的整数倍,所以最后内存大小为24。

示例2:交换成员位置

这次在示例1中struct的基础上交换了成员b和c的位置,输出结果就不一样了,分析如下:

根据上面的分析可知,struct2的成员总共需要16字节内存,根据规则3,struct2的内存大小必须是8(double a)的整数倍,所以最后内存大小为16。

示例3:结构体嵌套结构体

直接在struct1里加上一个struct2成员,然后输出内存大小

从之前struct1的分析可知,a、b、c、d实际占用18字节(位置0-17),那成员e就需要从位置18开始存放。由于e是个结构体,根据规则2, 当结构体作为成员时,需要从其内部最⼤元素所占内存⼤⼩的整数倍地址开始存储 。结构体e中内存占用最大的元素是 double a ,为8字节,所以e就需要从8的整数倍地址开始存储,即后移到位置24开始存储,e本身占用16字节内存,所以存放位置是24-39。

根据上面的分析可知,struct1的成员总共需要40字节内存,根据规则3,struct1的内存大小必须是8(double a)的整数倍,所以最后内存大小为40。

1. 数据结构 -- 共用体Union
2. 数据结构 -- 位域

结构体(struct)

结构体

  结构体是将不同类型的数据安装一定的功能需求进行整体封装,封装的数据类型与大小均可以由用户指定。

1 结构体的声明、定义及初始化

1.1 声明结构体类型

struct 结构体名
{
  成员列表;
};
struct STUDENT
{
  char name[20]; //名字
  int age;   //年龄
  char sex;  //性别
  int num;  //学号
  char add[30];  //家庭住址
  float score;   //分数
};

  1)结构体类型是由基本数据类型组合而成的新的数据类型。结构体类型的成员是由程序员自己定义的,所以结构体类型是由我们人为定义的数据类型

  2)struct STUDENT是定义的数据类型名字(与系统提供的int,char,float,double等提供的标准类型名一样,都是数据类型,具有相同的作用,都是用来定义变量的),它向编译系统声明这是一个结构体类型。

  3)声明结构体类型仅仅是声明了一个类型,系统并不为之分配内存,好比系统不会类型为int分配内存一样。只有当使用这个类型定义了的变量时,系统才会为变量分配内存。所以在声明结构体类型的时候,不可以对里面的变量进行初始化

1.2 定义结构体变量

  定义结构体变量有两种方法:

  1)先声明结"构体类型",再定义"结构体类型变量"

struct STUDENT stud1,stud2;

  stud1,stud2就是我们定义的结构体变量名。定义了结构体变量之后,系统就会为之分配内存单元

  2)声明结构体类型的同时定义结构体变量

struct STUDENT
{
  char name[20]; //名字
  int age;   //年龄
  char sex;  //性别
  int num;  //学号
  char add[30];  //家庭住址
  float score;   //分数
}stud;

  声明了一个结构体类型(struct STUDENT),并用这个类型定义了一个结构体变量stud。

  注:结构体变量不能相加、不能相减、不能相乘、不能相除。但结构体变量可以相互赋值,可以将一个结构体变量赋值给另一个结构体变量,前提是这两个结构体变量的结构体类型必须相同

1.3 结构体变量的引用

  由于结构体变量中有多个不同类型的成员,所以结构体变量成员不能整体引用,只能一个成员一个成员的引用。

  1)引用方式:

    结构体变量名.成员名

  2)可以引用"结构体变量成员"的地址,也可以引用"结构体变量的"地址

&stud1.num //stud1.num成员在内存中的首地址
&stud1     //stud1在内存中的首地址

  结构体变量的首地址,就是结构体第一个成员的首地址。&stud1等价于第一个成员name的首地址,而name是一个数组,数组名表示数组的首地址,所以&stud1与stud1.name是等价的。等价仅仅指的是它们表示"同一个内存空间的地址"但它们的类型是不同的,&stud1是结构体变量地址,是struct STUDENT*型的,而stud1.name是数组名,是char*型的,类型不同所以在程序中不能互换

2 结构体字节对齐

2.1 例一

#include <stdio.h>
struct DATA
{
  int m;
  char n;
}DATA;

int main()
{
  printf("%p,%p
",&DATA.m,&DATA.n);
  printf("%d
",sizeof(DATA));
}

/***********************************
输出:
      001A7560,001A7564
      8
************************************/

  我们看到DATA不是占5字节,而是占8字节。变量m的地址是从001A7560到001A7563占4字节;变量n的地址是从001A7564到 001A7567,也占4字节。m占4字节我们能理解,但n是char型,char型不是占1字节吗,这里为什么占4字节?其实不是它占了4字节,它占的还是1字节,只不过结构体中有一个字节对齐的概念。

  字节对齐:结构体是一种构造数据类型,里面可以有不同数据类型的成员。这些成员中,不同数据类型所占的内存空间不同。通过例子可以看出结构体变量成员分配内存不是顺序存储,而是按字节对齐的方式存储。即结构体成员中占内存最多的数据类型所占的字节数为标准,所有成员在分配内存是都要与这个长度对齐

m
n

 

 

 

所谓的空并不是里面什么都没有,它就同定义了一个变量没有初始化一样,里面是一个很小的负的填充字,在此只是为了便于表达。

2.2 例二

#include <stdio.h>
struct DATA
{
  int m;
  char n;
  char i;
}DATA;

int main()
{
  printf("%p,%p,&p
",&DATA.m,&DATA.n,&DATA.i);
  printf("%d
",sizeof(DATA));
}

/***********************************
输出:
      001A7560,001A7564,001A7565     
      8
************************************/
m
n i

 

 

 

3 结构体数组

  结构体数组的每一个元素都是一个结构体类型的变量,都包含结构体中的所有成员。

  1)定义结构体数组(同定义结构体变量一样,只不过将变量改为数组)

struct STUDENT stud[5];//定义了一个结构体数组,里面包含5个元素,每个元素都是一个结构体变量,包含结构体所有成员

for(i=0;i<5;i++)
{
  printf("%s%d %c%d",stud[i].name,stud[i].age,sutd[i].sex,stud[i].num);
}

  结构体数组的引用与引用一个结构体变量在原理上是一样的。只不过结构体数组中有多个结构体变量,只需利用for循 环一个一个地使用结构体数组中的元素。

4 结构体指针

4.1 指向结构体变量的指针

  指向什么结构体类型的结构体变量,就要定义成什么样的结构体类型。比如指向 struct STUDENT 类型的结构体变量,那么指针变量就一定要定义成 struct STUDENT* 类型

struct STUDENT *p //定义一个结构体指针变量
(*p).name //

  指针引用结构体变量成员方式:

    (*指针变量名).结构体成员名    或者   指针变量名->结构体成员名

  注:只有指针变量名后面才能加"->"

4.2 指向结构体数组的指针

  结构体数组的每一个元素都是一个结构体变量。如果定义一个结构体指针变量并把结构体数组的数组名赋给这个指针变量的话,就意味着将结构体数组的第一个元素,即第一个结构体变量的地址,也即第一个结构变量中的第一个成员的地址赋给了这个指针变量。

5 结构体类型的定义

结构类型无法将自己的类型作为其成员的类型,因为自己的类型定义尚不完整,要在结束的大括号(})后才算定义完整。然而,结构类型可以包含指向自己类型的指针,这样的应用很常见。例如,在实现链表(linked list)和二叉树(binary tree)时,就会用到这种自引用结构(self-referential structure)。

struct Cell
{ 
  struct Song song;        // 这条记录的数据
  struct Cell *pNext;      // 指向下一条记录的指针          
};

 

以上是关于数据结构 -- 结构体Struct的主要内容,如果未能解决你的问题,请参考以下文章

.有以下的结构体变量定义语句: struct student int num; c

Linux 内核 内存管理虚拟地址空间布局架构 ⑥ ( mm_struct 结构体源码 | vm_area_struct 结构体源码 )

Linux 内核进程管理 task_struct 结构体 ① ( task_struct 结构体引入 | task_struct 代码示例 )

typedef struct与struct定义结构体

C结构体struct用法小结

数据结构 -- 结构体Struct