【C语言督学训练营 第八天】有关结构体的那些事

一、结构体基本概念

有时候需要将不同类型的数据组合为一个整体,以便于引用。例如,一名学生有学号、姓名、性别、年龄、地址等属性,如果针对学生的学号、姓名、年龄等都单独定义一个变量,那么在有多名学生时,变量就难以分清。为此,C 语言提供结构体来管理不同类型的数据组合。

声明一个结构体类型的一般形式为

struct 结构体名
{成员表列};

例如,

struct student {
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};

先声明结构体类型,再定义变量名。例如,
struct student student1, student2;
看以下一个例子:

#include <stdio.h>
struct student{
    
    
	int num;
	char name[20];
	char sex;
	int age;
	float score;
	char addr[30];
}; //结构体类型声明,注意最后一定要加分号
int main()
{
    
    
	struct student s={
    
    1001,"lele",'M',20,85.4,"Shenzhen"}; //定义及初始化
	struct student sarr[3];
	int i;
	printf("%d %s %c %d %f %s\n",s.num,s.name,s.sex,s.age,s.score,s.addr);
	for(i=0;i<3;i++)
	{
    
    
		scanf("%d%s %c%d%f%s",&sarr[i].num,sarr[i].name,&sarr[i].sex,&sarr[i].age, &sarr[i].score,sarr[i].addr);
	}
	for(i=0;i<3;i++)
	{
    
    
		printf("%d %s %c %d %f %s\n",sarr[i].num,sarr[i].name,sarr[i].sex, sarr[i].age,sarr[i].score,sarr[i].addr);
	}
	return 0;
}

结构体类型声明要放在 main 函数之前,这样 main 函数中才可以使用这个结构体,工作中往往把结构体声明放在头文件中。注意,结构体类型声明最后一定要加分号,否则会编译不通。另外,定义结构体变量时,使用 struct student 来定义,不能只有 struct 或 student,否则也会编译不通,sarr 是结构体数组变量。结构体的初始化只能在一开始定义,如果 struct student s={1001,“lele”,‘M’,20,85.4,“Shenzhen”}已经执行,即 struct student s 已经定义,就不能再执行 s={1001,“lele”,‘M’,20,85.4,“Shenzhen”}。如果结构体变量已经定义,那么只能对它的每个成员单独赋值,如s.num=1003。

二、结构体大小计算方式(对齐)

结构体本身的对齐规则有好几条,比较难记,而且对于考研初试完全没有必要,考研初试只需要记住一条,结构体的大小必须是其最大成员的整数倍!

在没有#pragma pack这个宏的声明下,遵循下面三个原则:

  • 1、第一个成员的首地址为0.
  • 2、每个成员的首地址是自身大小的整数倍
  • 3、结构体的总大小,为其成员中所含最大类型的整数倍。
#include <stdio.h>
struct student_type1{
    
    
	double score;//double 是一种浮点类型,8 个字节,浮点分为 float 和 double,记住有这两种即可
	short age;
};
struct student_type2{
    
    
	double score;
	int height;
	short age;
};
struct student_type3{
    
    
	int height;
	char sex;
	short age;
};
int main() {
    
    
	struct student_type1 s1;
	struct student_type2 s2;
	struct student_type3 s3;
	printf("s1 size=%d\n",sizeof(s1));
	printf("s2 size=%d\n",sizeof(s2));
	printf("s3 size=%d\n",sizeof(s3));
	return 0;
}

在这里插入图片描述

三、结构体指针的使用方法

一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设置一个指针变量,
用它指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来
指向结构体数组中的元素,从而能够通过结构体指针快速访问结构体内的每个成员。

#include <stdio.h>
//结构体指针
struct student{
    
    
	int num;
	char name[20];
	char sex;
};
int main()
{
    
    
	struct student s={
    
    1001,"wangle",'M'};
	struct student sarr[3]={
    
    1001,"lilei",'M',1005,"zhangsan",'M',1007,"lili",'F'};
	struct student *p; //定义结构体指针
	int num;
	p=&s;
	printf("%d %s %c\n",p->num,p->name,p->sex);
	p=sarr;
	printf("%d %s %c\n",sarr[0].num,sarr[0].name,sarr[0].sex); //方式一获取成员
	printf("%d %s %c\n",(*p).num,(*p).name,(*p).sex); //方式一获取成员
	printf("%d %s %c\n",p->num,p->name,p->sex); //方式二获取成员
	printf("------------------------------\n");
	p=p+1;
	printf("%d %s %c\n",p->num,p->name,p->sex);
	return 0;
}

p 就是一个结构体指针,可以对结构体 s 取地址并赋给 p,这样借助成员选择操作符,就可以通过 p 访问结构体的每个成员,然后进行打印。我们知道数组名中存储的是数据的首地址,所以可以将 sarr 赋给 p,这样就可以通过两种方式访问对应的成员。使用(p).num 访问成员为什么要加括号呢?原因是“.”成员选择的优先级高于“”(即取值)运算符,所以必须加括号,通过*p 得到 sarr[0],然后获取对应的成

四、结构体重命名

前面定义结构体变量时使用的语句是 struct student s,以这种方式来定义结构体变量有些麻烦,即每次都需要写 struct student。那么有没有简单一些的定义方式呢?答案是肯定的,可以选择使用 typedef 声明新的类型名来代替已有的类型名。

#include <stdio.h>
//结构体指针
typedef struct student{
    
    
	int num;
	char name[20];
	char sex;
}stu,*pstu;
typedef int INTEGER;
int main()
{
    
    
	stu s={
    
    1001,"wangle",'M'};
	pstu p;
	INTEGER i=10;
	p=&s;
	printf("i=%d,p->num=%d\n",i,p->num);
	return 0;
}

使用 stu 定义结构体变量和使用 struct student 定义结构体变量是等价的;使用 INTEGER定义变量 i 和使用 int 定义变量 i 是等价的;pstu 等价于 struct student*,所以 p 是结构体指针变量。


在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/apple_51931783/article/details/129893792