C语言:结构体详解(简单易懂)

文章目录

  • 结构体类型的声明
    • 结构的基础知识
    • 结构体的声明
    • 结构成员的类型
    • 结构体变量的定义和初始化
  • 结构体成员访问
  • 结构体传参

前言:

我们在前面的C语言学习过程中,学习了各种数据类型,例如:整型数据类型、字符型数据类型,浮点型数据类型等,这些数据类型的设计都是为了对实际生活中的各种数据进行在计算机上的储存,但我们生活中还有一些数据无法使用以上单一的数据类型进行描述,例如;如何在计算机上保存一个人的信息,一个人的信息包括名字(字符)、年龄(整型),身高(浮点型)、体重(浮点型)等等。此时,C语言就设计出了结构体来对一些复杂的数据进行描述及数据的储存。

结构体类型的声明

结构的基础知识

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

结构体的声明

struct tag
{
 	member-list;
}variable-list;//注意这里的分号不要漏写

在这里插入图片描述

举个例子:

描述一个学生的信息。

struct Stu
{
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
	char id[10];//学号
}s1;//结构体成员变量

在这里插入图片描述

结构成员的类型

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

结构体变量的定义和初始化

有了结构体类型,那如何定义变量,其实很简单。

结构体变量的定义有两种:

  1. 在创建结构体的同时定义结构体变量。
  2. 在结构体的外边定义结构体变量。
#include 
struct Point
{
	int x;
	int y;
}p1; //声明类型的同时定义变量p1(第一种定义方式)

struct Point p2; //定义结构体变量p2(第二种定义方式)

struct Point p3 = { 1, 2 };//初始化:定义变量的同时赋初值。


struct Stu//类型声明
{
	char name[15];//名字
	int age;//年龄
};
struct Stu s = { "zhangsan", 20 };//初始化


struct Node
{
	int data;
	struct Point p;//结构体嵌套
	struct Node* next;
}n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化

struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化

结构体成员访问

我在之前的C语言操作符详解文章中详细讲解过结构体成员访问操作符,这里就简要介绍一下,不过多赘述了,有兴趣的可以看下我之前的文章:

  • 文章链接:C语言:操作符详解

结构体成员访问操作符分为点操作符(.)箭头操作符(->)

结构体成员访问操作符接受两个操作数。

使用格式:

  • .

    结构体.成员名

  • ->

    结构体指针->成员名

举例:点操作符

#include 
struct stu
{
	char name[15];
	int age;
};

int main()
{
	struct stu s1 = { "zhangsan", 20 };//定义及其初始化
	printf("%s %d\n", s1.name, s1.age);
	//通过点操作符(.)访问到结构体变量s1中的name成员
	//通过点操作符(.)访问到结构体变量s1中的age成员
	return 0;
}

在这里插入图片描述

注意:

如果你在结构体定义初始化的时候不按照结构体内部成员变量的顺序来初始化的时候,就需要使用点操作符来指向对应的结构体成员。

#include 
struct stu
{
	char name[15];
	int age;
};

int main()
{
	struct stu s1 = { "zhangsan", 20 };
	struct stu s2 = { .age = 20, .name = "zhangsan" };
	printf("%s %d\n", s1.name, s1.age);
	printf("%s %d\n", s2.name, s2.age);
	return 0;
}

在这里插入图片描述


举例:箭头操作符

#include 
struct stu
{
	char name[15];
	int age;
};

int main()
{
	struct stu s1 = { "zhangsan", 20 };//定义及其初始化
	struct stu* p1 = &s1;//结构体指针p1指向s1的地址
	printf("%s %d\n", p1->name, p1->age);
	//通过箭头操作符(->)通过p1指针访问到结构体变量s1中的name成员
	//通过箭头操作符(->)通过p1指针访问到结构体变量s1中的age成员
	return 0;
}

在这里插入图片描述

结构体传参

当我们需要把结构体传到某一个函数内部调用时,就涉及到结构体传参的知识。

举例:

设计一个print函数来打印结构体的内容。

函数调用时,函数传参分为传值调用和传址调用。

如果你不太了解,这里放上我的另一篇文章,里面详细介绍了有关函数的相关知识,有兴趣的可以点击阅读:

  • 文章链接:C语言:函数详解

这里我们用两种形式分别实现一下:

传值调用:

#include 
struct stu
{
	char name[15];
	int age;
};

//结构体传参
void print(struct stu s)
{
		printf("%s %d\n", s.name, s.age);
}
int main()
{
	struct stu s1 = { "zhangsan", 20 };//定义及其初始化
	print(s1);//结构体传值
	return 0;
}

在这里插入图片描述

我们知道,函数传参时使用传值调用,形参是实参的一份临时拷贝

所以这里在结构体s1传参的时候,其实是把s1的内容完全复制了一份让print函数中的结构体s来接收,打印的是s中拷贝的s1的内容。


传址调用:

#include 
struct stu
{
	char name[15];
	int age;
};

//结构体地址传参
void print(struct stu* s)
{
	printf("%s %d\n", s->name, s->age);
}
int main()
{
	struct stu s1 = { "zhangsan", 20 };//定义及其初始化
	print(&s1);//结构体传址
	return 0;
}

在这里插入图片描述

函数传参时使用传址调用,形参是实参的地址

所以这里在结构体s1传参的时候,其实是把s1的地址传过去,print函数中的结构体指针s接受s1的地址,然后通过箭头操作符,通过指针s找到s1的空间,最后打印的是s1的内容。


思考:

上面的两种传参函数哪个好些?

答案是:首选传址调用的函数。

原因:

函数传参的时候,参数是需要压栈的。

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

结论:

结构体传参的时候,尽量要传结构体的地址。


本篇关于C语言结构体的讲解就到此结束了,感兴趣的的小伙伴点点赞,点点关注,谢谢大家的阅读哦!!!

但是对于结构体的知识还不止这些,关于结构体内存对齐、结构体实现位段、枚举和联合的讲解会放在后边继续介绍,点点关注,后期不错过哦。😘


我相信大家在编写代码的时候常常会出现各种各样的错误,但又不知道错误在哪,搞得自己痛苦不堪,本博主告诉你不用担心,我下一篇将会对代码的实用调试技巧出一篇文章,详细介绍各种调试工具,帮助你更好的发现问题,解决问题哦。

你们的鼓励就是我的动力,欢迎下次继续阅读!!!😘😘😘

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/3642d96449.html