从零开始C语言精讲篇6:结构体


在这里插入图片描述

提示:以下是本篇文章正文内容,下面案例可供参考

一、结构体类型的声明

1.1结构的基础知识

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量

我们现在已经学了char、int、short、float等等类型,但是这些类型都是孤立的。
如果你想描述一个复杂对象,比如你描述一本书,书有价格、书名、作者、出版号…

为了能够描述复杂对象,就有了结构体。
而因为复杂对象有着不同的属性,所以就有了不同的成员变量,不同的成员变量可能有不同类型

1.2结构的声明

struct tag
{
 member-list;//成员列表
}variable-list;//变量列表,可以有,可以没有

例如描述一本书

struct Book
{
	char name[20];
	char author[15];
	float price;
};//这里是有一个分号的,别忘记了

1.3结构成员的类型

结构的成员可以是标量、数组、指针,甚至是其他结构体。

二、结构体变量的定义及初始化

2.1结构体的变量的定义

#include<stdio.h>
struct Book
{
	char name[20];
	char author[15];
	float price;
}b1,b2;//可以直接在结构体后面创建(一个或多个)变量
//这里的b1,b2是全局变量,在静态区
int main()
{
    //struct Book 看做一个类型
	struct Book b3;//也可以在main函数里创建变量
	//这里的b3是局部变量,在栈区
	return 0;
}

如果你嫌每次都写 “struct 结构体名” 来创建变量麻烦,可以使用typedef来对类型重命名

typedef struct Student
{
	char name[20];
	int age;
	char id[20];
}Stu;//把类型struct Student重命名为Stu
//Stu后面不可以再跟变量了(重命名之后就不允许有变量列表了)

int main()
{
	struct Student s1;
	Stu s2;//s1和s2是一个类型
	return 0;
}

2.2结构体的变量的初始化

struct Student
{
	char name[20];
	int age;
	char id[20];
};
int main()
{
	struct Student s1 = {"张三",20,"2016486001"};
	struct Student s2 = {"李四",19,"2016486002"};
	return 0;
}

可能会遇到嵌套定义的情况,那我们初始化也需要嵌套一下

struct M
{
	int a;
	char b;
};

struct N
{
	struct M m;
	float c;
};
int main()
{
	struct N t = { {1,'x'},3.14 };
	return 0;
}

声明是不会占空间的,定义则会占空间。
声明就相当于造房子的图纸,而定义则是把按图纸把房子建出来。

三、结构体成员的访问

结构体变量访问成员 结构变量的成员是通过点操作符(.)访问的。
点操作符接受两个操作数。例如:

struct M
{
	int a;
	char b;
};


struct N
{
	struct M m;
	float c;
};
int main()
{
	struct N t = { {1,'x'},3.14 };
	printf("%d\n", t.m.a);//可以再用一次点号“.”来对里层结构体成员访问
	printf("%c\n", t.m.b);
	printf("%f\n", t.c);
	return 0;
}

在这里插入图片描述

但有时,我们拿到的不是结构体本身,而是结构体的地址。
这时,如果我们想访问结构体成员怎么办?

struct M
{
	int a;
	char b;
};


struct N
{
	struct M m;
	float c;
};
int main()
{
	struct N t = { {1,'x'},3.14 };

	//printf("%d\n", t.m.a);//也可以再用一次点号“.”来对里层结构体成员访问
	//printf("%c\n", t.m.b);
	//printf("%f\n", t.c);

	struct N* pt = &t;//获取结构体t的地址
	//法一
	printf("%d %c %f\n",(*pt).m.a, (*pt).m.b, (*pt).c);
	//*pt,对pt进行解引用,就得到了t,(*pt).m就相当于t.m

	//法二
	printf("%d %c %f\n", (pt->m).a, (pt->m).b,pt->c);
	//pt是指向结构体t的指针,m是结构体t的成员变量
	//我们规定一种写法pt->m就相当于t.m
	return 0;
}

在这里插入图片描述

四、结构体传参

请看下面代码:

struct S
{
	int data[1000];
	int num;
};
struct S s = { {1,2,3,4}, 1000 };
//结构体传参
void print1(struct S s)
{
	printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
	printf("%d\n", ps->num);
}
int main()
{
	print1(s);  //传结构体
	print2(&s); //传地址
	return 0;
}

在这里插入图片描述
上面的 print1 和 print2 函数哪个好些?
答案是:首选print2函数。 原因:

函数传参的时候,参数是需要压栈的。 如果传递一个结构体对象的时候,结构体过大,参数压栈
的的系统开销比较大,所以会导致性能的下降。

但是如果你传的参数仅仅是个地址,也就是4个字节(64位下8字节)啊,这个对性能来说友好很多

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

劲夫学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值