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



    在这里插入图片描述

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

    一、结构体类型的声明

    1.1结构的基础知识

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

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

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

    1.2结构的声明

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

    例如描述一本书

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

    1.3结构成员的类型

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

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

    2.1结构体的变量的定义

    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    如果你嫌每次都写 “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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

    struct M
    {
    	int a;
    	char b;
    };
    
    struct N
    {
    	struct M m;
    	float c;
    };
    int main()
    {
    	struct N t = { {1,'x'},3.14 };
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

    三、结构体成员的访问

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

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

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

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

    四、结构体传参

    请看下面代码:

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

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

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

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

  • 相关阅读:
    C++对象池
    高级查询
    【原创】只用Asp.NET Core Web API与Vue 3.0搭建前后分离项目
    未定义与 ‘double‘ 类型的输入参数相对应的函数 ‘Link‘
    VMware中Ubuntu(Linux)无法连接网络解决办法记录
    DC-DC选型及电路设计
    基于邻接矩阵的广度优先遍历
    全排列与组合
    2022年中总结
    springboot毕设项目高校招生预报管理系统f10sf(java+VUE+Mybatis+Maven+Mysql)
  • 原文地址:https://blog.csdn.net/m0_57180439/article/details/126146340