前言:
我们在前面的C语言学习过程中,学习了各种数据类型,例如:整型数据类型、字符型数据类型,浮点型数据类型等,这些数据类型的设计都是为了对实际生活中的各种数据进行在计算机上的储存,但我们生活中还有一些数据无法使用以上单一的数据类型进行描述,例如;如何在计算机上保存一个人的信息,一个人的信息包括名字(字符)、年龄(整型),身高(浮点型)、体重(浮点型)等等。此时,C语言就设计出了结构体来对一些复杂的数据进行描述及数据的储存。
结构体类型的声明
结构的基础知识
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
结构体的声明
struct tag
{
member-list;
}variable-list;//注意这里的分号不要漏写
举个例子:
描述一个学生的信息。
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[10];//学号
}s1;//结构体成员变量
结构成员的类型
结构的成员可以是标量、数组、指针,甚至是其他结构体。
结构体变量的定义和初始化
有了结构体类型,那如何定义变量,其实很简单。
结构体变量的定义有两种:
- 在创建结构体的同时定义结构体变量。
- 在结构体的外边定义结构体变量。
#include <stdio.h>
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 <stdio.h>
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 <stdio.h>
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 <stdio.h>
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 <stdio.h>
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 <stdio.h>
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://www.toymoban.com/news/detail-789562.html
我相信大家在编写代码的时候常常会出现各种各样的错误,但又不知道错误在哪,搞得自己痛苦不堪,本博主告诉你不用担心,我下一篇将会对代码的实用调试技巧出一篇文章,详细介绍各种调试工具,帮助你更好的发现问题,解决问题哦。
你们的鼓励就是我的动力,欢迎下次继续阅读!!!😘😘😘文章来源地址https://www.toymoban.com/news/detail-789562.html
到了这里,关于C语言:结构体详解(简单易懂)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!