结构体详解

结构体

什么是结构体

结构体是一种用户自定义的数据类型,可以组合多个相关值成为一个单一类型。它是由一批数据组合而成的结构型数据,结构体可以包含多个不同类型的字段,如基本数据类型、其他结构体、枚举类型等。在Rust中,结构体有着重要的作用,可以创建更复杂的数据结构,并定义它们的行为。结构体使用struct关键字定义,如`struct Person { name: String, age: i32, }`。结构体实例的创建需要使用构造函数。结构体字段可以是可变的,也可以是不可变的,默认情况下,结构体字段不可变。如需修改结构体字段,需要使用mut关键字。结构体也可以绑定方法,方法允许你以面向对象的方式操作结构体实例。结构体还提供了一种更新语法,使用..运算符(也称为点运算符或展开运算符)。结构体在不同的编程语言中都有类似的实现,如C++和Rust等。 

结构体的解释

结构体(Structure)是C语言中一种组织多个变量的方式,它允许我们将不同的数据类型组合在一起,形成一个单一的实体。
结构体在内存中占用的空间等于其所有成员占用的空间之和。
在C语言中,结构体是通过关键字 `struct` 定义的
下面是一个简单的结构体定义的例子:

struct Person {
    char name[50];
    int age;
    float height;
};

在这个例子中,我们定义了一个名为 `Person` 的结构体,它包含三个成员:`name`(字符数组,用于存储姓名),`age`(整型,用于存储年龄),和 `height`(浮点型,用于存储身高)。
要使用这个结构体,我们可以声明一个 `Person` 类型的变量:

struct Person p1;

然后,我们可以像访问普通变量一样访问 `p1` 的成员:

p1.name = "Alice";
p1.age = 30;
p1.height = 165.5;

我们也可以通过指针来访问结构体的成员,这可以提高代码的灵活性:

struct Person *p2;
p2 = &p1;
printf("%s\n", p2->name); // 输出: Alice

在上述代码中,`p2` 是一个指向 `Person` 结构体的指针。通过 `->` 操作符,我们可以访问它指向的结构体的成员。
结构体在实际编程中的应用非常广泛,例如,它可以用来表示现实世界中的对象或实体,如学生、员工等,每个实体都有其相应的属性。结构体也可以用来组织数据,使得数据管理更加方便和高效。

结构体的基本知识

结构是值的变量

也就是值的集合,这些集合称之为成员变量

数组一组相同元素的集合

结构体是一组不一定相同类型的元素的集合

复杂的对象不能通过简单的内置类型直接描述和表示 此时就有了结构体 来描述复杂类型

结构体的声明

但是需要知道的是,在函数体里面写的名字 ,如果要这个在其他函数进行使用,要么使用函数声明,要么把结构体放到最上面。

因为C语言的运行程序是从上往下进行运行的,但是进行函数的声明之后,就会先进行一次程序走一遍,再继续运行。

struct tag是名字//tag是名字 结构体是本身是不需要进行头文件的

{

}

大括号里面是成员 可以是多个 也可以是0个

最后是变量列表

举例 描述一个学生

一个汉字两个字符串

这个就是结构体类型

———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— 

结构体的初始化

有了类型 才可以初始化

此时也就完成了结构体的初始化

这个是在main函数里面的初始化

当然这个不仅可以在main函数里面进行初始化 ,也可以在结构体下面的函数连进行初始话

初始化的时候就是 struct + 函数体名字(Stu) 在主函数里面 这个时候就再加上一个名字 arr等任意名字 就按照数组的方式可以进行初始化

也就是 可以是struct + Stu+si;

也可以是struct + Stu+arr;在主函数里面

在C语言中,结构体的初始化可以通过几种方式来完成,包括逐字段初始化、使用结构体数组、使用`malloc`分配内存后初始化,以及使用`memset`或`bzero`对内存块进行初始化。

1.
逐字段初始化
逐字段初始化是最直接的方法,直接为结构体的每个字段赋值例如:
struct Person {
    char name[50];
    int age;
    float height;
};
struct Person p1 = {"张三", 30, 165.5f};//按照顺序 也就是 name=张三,age=年龄,heihgt=身高



2.
 使用结构体数组
如果你有一系列结构体实例,你可以使用结构体数组来初始化它们:

struct Person students[3] = {
    {"Bob", 22, 175.0f},
    {"Charlie", 24, 180.0f},
    {"David", 23, 172.0f}
};


3.
使用`malloc`分配内存后初始化
如果你需要在程序运行时动态分配结构体的内存,你可以使用`malloc`函数,然后手动为每个字段赋值:
struct Person *p2 = (struct Person *)malloc(sizeof(struct Person));
if (p2 != NULL) {
    strcpy(p2->name, "Bob");
    p2->age = 22;
    p2->height = 175.0f;
}


4.
使用`memset`或`bzero`初始化
在某些情况下,你可能需要初始化整个结构体或结构体数组的全部字段,这时可以使用`memset`或`bzero`函数。`memset`将内存中的字节设置为指定的值,而`bzero`只是将内存中的字节设置为0(清零)。
struct Person p3;
memset(&p3, 0, sizeof(struct Person)); // 将p3的字段全部初始化为0
// 或者使用bzero
bzero(&p3, sizeof(struct Person)); // 将p3的字段全部初始化为0
请注意,使用`memset`或`bzero`时,要确保传递的地址是指向结构体的指针,而不是结构体本身。
这些是结构体初始化的常见方法。根据具体的需求和场景,你可以选择最适合你的初始化方式。

结构体的类型和变量

比喻

这个是图纸和房子的关系

结构体就是图示 主函数里面的初始化和框架也就是开始建立房子

类型和变量的关系(局部变量和全局变量)

这里也就是char name[100]所以占用的空间大一点

int age是整形 占据四个字节或者八个字节

char sex[5]又比int大一点

有了类型之后在主函数里面创建s1

这里的s2 s3 s4 就是结构体变量 这三个是函数外面创建的 也就是全局变量 和s1一样 但是s1 是局部变量 但是s2,s3,s4是结构体的全局变量

代码举例
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct Stu
{
	char name[100];//这里看理解为名字 一个汉字占两个字符
	int age;//这里可以设置成整形 因为这里是名字的意思 
};
struct Stu s3[4] = { {"张三",12} ,{"lisi",23}, {"王五",2}, {"二狗",1} };
struct Stu s4[4] = { {"张三",12} ,{"lisi",23}, {"王五",2}, {"二狗",1} };

void test()
{
	struct Stu s2[4] = { {"张三",12 } ,{"lisi",23}, {"王五",2}, {"二狗",1} };

}

int main()
{
	//此时如果是在main函数里面 或者在test();函数里面创建的结构体变量,此时是局部变量 也就是cs1 s2
	//如果是在结构体外部创建的变量 此时是全局变量 也就是 s3 s4
	struct Stu s1[4] = { {"张三",12 } ,{"lisi",23}, {"王五",2}, {"二狗",1} };

	
	return 0;
}

———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— 

typedef

 typedef的使用
在编程中,`typedef` 是一个关键字,用于为已存在的数据类型创建一个别名。这样做可以让代码更易于阅读和维护,特别是在处理复杂或者冗长的类型名称时。
例如,在 C 语言中,您可以使用 `typedef` 为标准数据类型如 `int` 创建别名:

typedef int INT32; // 将 int 类型重命名为 INT32

之后,您就可以使用 `INT32` 代替 `int` 来声明变量:

INT32 a, b; // 这里实际上是指 int 类型的变量

在不同的编程语言中,`typedef` 的作用和用法可能会有所不同,但核心概念是类似的,都是为了简化代码中对数据类型的引用。

typedef对变量重命名 但是需要知道 C语言里面 如果没有对结构体类型进行typedef,struct是不能省略的

也就是如果存在typedef 结构体后面的stu是一个类型


例如,如果我们有一个结构体:

struct Student {
    char name[50];
    int age;
    float score;
};

我们可以使用 `typedef` 为这个结构体定义一个新的类型名称:

typedef struct Student stu;

这样,`stu` 就成为了 `struct Student` 的一个别名。之后,你就可以使用 `stu` 来声明这个结构体的变量:

stu s1;

这里,`s1` 是一个 `struct Student` 类型的变量,但使用了 `stu` 作为它的类型名称。
所以,如果你看到代码中有 `typedef struct Student stu;`,那么 `stu` 就是一个代表 `struct Student` 类型的别名。

或者 

———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— 

结构体的成员访问

结构体是可以互相包含的

可以在上一个 结构体里面 定义一个新的 结构体类型

上面我们知道在结构体外面创建的结构变量的全局变量

但是其实在这个外面创建的全局变量也是可以直接进行初始化的 

在全局变量和局部变量里面的代码举例里面进行了举例

举例

在s1里面进行修改

初始化 并且给他一些数值

初始化 逐步初始化,

100 字符 空指针

struct S +名字s2 然后初始化 括号{} 和 数组的初始化有些类似

这里依旧是结构体的初始化的举例

选择初始化

.选择 中间       ,      隔开

.的方式找到成员

这里需要记住

1   .  是  结构成员访问操作符 .

2   ->是结构成员访问操作符 .

重复一下

1   .  是  结构成员访问操作符 .

2   ->是结构成员访问操作符 .

 这里打印的是这三个

如果是需要进行这个多个结构体的访问和打印 需要用上循环

struct的B sb进行初始化和成员访问

怎么放里面怎么拿出来

也就是如何打印出来 这里需要一一对应的方式打印出来,哪怕是进行循环打印,这个结构体里面的数值也要进行一一对应的方式进行打印

下面打印的是结构体B 初始化函数名sb 

打印的时候就是sb.ch//意思就是sb下的struct ch

同理打印结构体第二个数值 也就是sb.s.a//意思就是struct B 结构体创建的sb下的,struct B里面的struct S s。

数值的传递

这里是直接把结构体传参过去了 传到set_stu函数里面 在后期会用得上

但是记得,在传参的时候需要带上struct+名字 +初始化的名字 

进行拷贝

把张三拷贝到name里面去

strcpy是拷贝函数(记着就行)

包含头文件string.h

此时set_stu就成功的把函数拷贝过来了
语法形式记着就可以

strcmp的解释

在C语言中,`strcpy` 函数用于将一个字符串复制到另一个字符串中。它的原型定义在 `string.h` 头文件中。`strcpy` 函数的语法格式如下:

char *strcpy(char *dest, const char *source);

参数说明:
- `dest`:指向目标字符串的指针,即要复制字符串到的位置。
- `source`:指向源字符串的指针,即要复制的字符串。
`strcpy` 函数会复制 `source` 指向的字符串到 `dest` 指向的空间中,包括字符串结束符 `\0`。注意,目标字符串数组必须有足够的空间来容纳源字符串,否则可能会导致缓冲区溢出。
示例用法:

#include <stdio.h>
#include <string.h>
int main() {
    char dest[20];
    const char *source = "Hello, World!";
    // 将源字符串复制到目标字符串中
    strcpy(dest, source);
    printf("复制后的目标字符串: %s\n", dest);
    return 0;
}

在这个例子中,`strcpy` 函数将 "Hello, World!" 复制到 `dest` 数组中,然后程序打印出复制后的字符串。

回归主体 

打印结构体s

t.什么什么 ,这个t其实就是创建的形参可以理解为

但是此时是错误

因为结构体是需要明确指向哪个地址的

画图解析原因

此时需要解决需要传址

在指针(1)指针篇章-(1)-CSDN博客里面解释了什么是传址 什么是传值

&s

这样就是正确的

这里指向的不是打印是age和name而是struct stu里面的name和age

这里也需要取地址名字s 然后指向这个位置 打印出来 这样打印的才是正确 

升级版本 箭头 结构体成员

打印结构体的代码以及结构体传参

 不包含循环的打印

此时也就是指针指向的是首元素的地址 所以打印的时候也就是打印的首元素的地址

要是想循环打印出内容的情况下 只需要在外部加个for循环 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct Stu
{
	char name[100];//这里看理解为名字 一个汉字占两个字符
	int age;//这里可以设置成整形 因为这里是名字的意思 
};
struct Stu s3[4] = { {"张三",12} ,{"lisi",23}, {"王五",2}, {"二狗",1} };
struct Stu s4[4] = { {"张三",12} ,{"lisi",23}, {"王五",2}, {"二狗",1} };

void test(struct Stu *ps)//这里调用的是main函数里面的结构体进行打印 
{
	printf("%s %d\n", ps->name, ps->age);
}

int main()
{
	//此时如果是在main函数里面 或者在test();函数里面创建的结构体变量,此时是局部变量 也就是cs1 s2
	//如果是在结构体外部创建的变量 此时是全局变量 也就是 s3 s4
	struct Stu s1[4] = { {"张三",12 } ,{"lisi",23}, {"王五",2}, {"二狗",1} };
	test(&s1);
	struct Stu s2[4] = { {"zhangsan",12 } ,{"lisi",23}, {"王五",2}, {"二狗",1} };
	test(&s2);

	return 0;
}

循环打印出结构体

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct Stu
{
	char name[100];//这里看理解为名字 一个汉字占两个字符
	int age;//这里可以设置成整形 因为这里是名字的意思 
};
struct Stu s3[4] = { {"张三",12} ,{"lisi",23}, {"王五",2}, {"二狗",1} };
struct Stu s4[4] = { {"张三",12} ,{"lisi",23}, {"王五",2}, {"二狗",1} };

void test(struct Stu *ps)//这里调用的是main函数里面的结构体进行打印 
{
	printf("%s %d\n", ps->name, ps->age);
}

int main()
{
	//此时如果是在main函数里面 或者在test();函数里面创建的结构体变量,此时是局部变量 也就是cs1 s2
	//如果是在结构体外部创建的变量 此时是全局变量 也就是 s3 s4
	struct Stu s1[4] = { {"张三",12 } ,{"lisi",23}, {"王五",2}, {"二狗",1} };
	int sz1 = sizeof(s1) / sizeof(s1[0]);
	for (int i = 0; i < sz1; i++)
	{
		test(&s1[i]);
	}
	printf("\n");
	struct Stu s2[4] = { {"zhangsan",12 } ,{"lisi",23}, {"王五",2}, {"二狗",1} };
	int sz2 = sizeof(s2) / sizeof(s2[0]);
	for (int i = 0; i < sz2; i++)
	{
		test(&s2[i]);

	}

	return 0;
}

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

结构体传参 

传值


   当结构体作为函数参数时,如果使用传值方式,那么函数将接收一个结构体变量的副本。这意味着在函数内部对结构体的修改不会影响到原始的结构体变量。因为在函数调用时,会创建一个结构体的副本并传递给函数,函数操作的是这个副本,而不是原始数据。
   示例: 


   
   struct Student {
       char name[50];
       int age;
   };
   void printStudent(struct Student s) {
       printf("Name: %s, Age: %d\n", s.name, s.age);
   }
   int main() {
       struct Student student = {"Alice", 20};
       printStudent(student);  // 调用时传递的是student的副本
       return 0;
   }
 

 

传址


   当使用传址方式时,函数接收的是结构体变量的地址。这意味着在函数内部对结构体的修改会影响到原始的结构体变量,因为函数操作的是存储在原始地址中的数据。
   示例:
  


   struct Student {
       char name[50];
       int age;
   };
   void modifyStudent(struct Student *s) {
       strcpy(s->name, "Bob");  // 修改的是传入的结构体变量
       s->age = 21;
   }
   int main() {
       struct Student student = {"Alice", 20};
       modifyStudent(&student);  // 传递的是student的地址
       printf("Name: %s, Age: %d\n", student.name, student.age);  // 输出已修改的值
       return 0;
   }

总结

 在实际编程中,通常根据是否需要修改原始数据来选择使用传值还是传址。如果函数需要修改结构体数据,或者结构体较大,为了节省内存和提高效率,通常使用传址方式。如果函数只是读取结构体数据,而不进行修改,使用传值方式即可。

原因函数传参的时候 参数压栈 参数过大的时候 压栈就过大 不仅浪费空间 而且浪费时间

如果直接传递地址过去 无非就是四个或者八个字节 只要有一个指针大小的空间就够了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/430747.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubantu 18.04 配置固定IP

1.首先在终端里输入命令,将你的网关和ip&#xff0c;记下来 ifconfig 2. 执行命令&#xff1a; sudo gedit /etc/network/interfaces 3.在弹出来的框里输入 auto后面的就是网关&#xff0c;address是你虚拟机的ip&#xff0c;gateway是你的网关ip&#xff0c;netmask是你的子…

Python从0到100(二):Python语言介绍及第一个Pyhon程序

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

如何通过抖捧轻松开启AI常态化自动直播间

在如今的互联网时代&#xff0c;短视频和直播已成为大多数企业与实体商家必备的经营技能&#xff0c;不只是全国头部的品牌&#xff0c;他们纷纷加码直播&#xff0c;更有一些已经开启了直播矩阵的体系&#xff0c;包括中小型的商家&#xff0c;他们也在考虑一件事情&#xff0…

前端接收流,并下载到本地

碰到一个大坑&#xff0c;附件文件存在华为云上&#xff0c;查询列表里记录的附件给了一个https开头的url&#xff0c;要求点击附件图标&#xff0c;下载附件到本地&#xff0c; 思路1.直接<a hrefurl downloadfileName >下载</a> 实际效果&#xff1a;跨域下载不…

Java批量修改文件目录名称(树行结构、批量重命名)

Java批量修改文件目录名称(树行结构、批量重命名) 1.读取某个路径的文件目录结构 2.递归批量修改目录文件前缀进行递增 3.结果截图 4.代码 package com.zfi.server.device;import java.io.File; import java.util.Arrays; import java.util.Comparator;public class FileTest…

【ArcPy】游标访问几何数据

访问质心坐标相关数据 结果展示 代码 import arcpy shppath r"C:\Users\admin\Desktop\excelfile\a2.shp" with arcpy.da.SearchCursor(shppath, ["SHAPE","SHAPEXY","SHAPETRUECENTROID","SHAPEX","SHAPEY",&q…

2024抖店全新教程,关于选品和对接达人的流程,细节分享如下

我是王路飞。 对做无货源抖店的商家来说&#xff0c;如何找到一个好的产品&#xff0c;并且把它卖出去&#xff0c;非常重要。 因此&#xff0c;商家的选品能力、达人资源的对接&#xff0c;就很关键了。 今天给你们聊下2024年做抖店&#xff0c;如何选品并且对接到靠谱的带…

MySQL王国:从基础到高级的完整指南【文末送书-28】

文章目录 MySQL从入门到精通第一部分&#xff1a;MySQL基础第二部分&#xff1a;MySQL进阶第三部分&#xff1a;MySQL高级应用 MySQL从入门到精通&#xff08;第3版&#xff09;&#xff08;软件开发视频大讲堂&#xff09;【文末送书-28】 MySQL从入门到精通 MySQL是一种开源…

记录开发过程中遇到的oracle 分页问题

问题: oracle 分页查询,因为是相对来说比较复杂的sql,一直以为是union all 的问题. 结果是相同时间相同,order by 时间之后 、分页查询的每次结果都不能保证与自己直接查询的不分页数据保持一致、导致有些数据看不到 解决方案: order by 条件最后添加一个表中不会重复的字段比如…

复合机器人上下料方案:从设计到实施的全过程

随着智能制造和工业自动化的快速发展&#xff0c;复合机器人上下料方案已成为提高生产效率、降低人力成本的关键技术。 方案设计 1、需求分析&#xff1a;首先&#xff0c;需要对生产线的上下料需求进行深入分析&#xff0c;包括物料种类、尺寸、重量、上下料频率等&#xff…

八大技术架构演进之路【小林优选,呕心沥血】

概述 在进行技术学习过程中&#xff0c;由于大部分读者没有经历过一些中大型系统的实际经验&#xff0c; 导致无法从全局理解一些概念&#xff0c;所以本文以一个 "电子商务" 应用为例&#xff0c;介绍从一百个 到千万级并发情况下服务端的架构的演进过程&#xff0c…

三级分销数据库设计

一&#xff0c;数据结构 二&#xff0c;查询方法 1.mysql递归查询 获取id9的所有上级 r : 9 设置自己所要搜索子节点的id SELECTT2.* FROM(SELECTr AS _id,( SELECT r : pid FROM sj_user WHERE id _id ) AS 2v2,l : l 1 AS lvl FROM( SELECT r : 9 ) vars, -- 查询id为…

MS2351M——RF 检测器/控制器

产品简述 MS2351M 是一款对数放大器芯片&#xff0c;主要用于接收信号强度 指示 RSSI 与功率放大器控制&#xff0c;工作频率范围是 50M  3000MHz &#xff0c; 因频率与温度不同&#xff0c;动态范围达 35dB 到 45dB 。 MS2351M 是电压响应器件&#xff0c; 50M…

哪些大型国企会储备GIS开发工程师?

随着数字化技术的不断发展和国家对数字化转型的重视&#xff0c;国企作为国民经济的中坚力量&#xff0c;开始走在数字化转型的前列。 许多国企&#xff0c;已经将数字化转型作为企业发展的重点战路&#xff0c;希望通过数字化技术的应用&#xff0c;推动企业的业务模式、管理…

Java8的Stream执行机制

Java8的Stream执行机制 Stream的概念解说Stream的概念解说-Stream的含义Stream的概念解说-现实类比Stream的概念解说-Stream中的概念Stream的执行机制Stream的执行机制-最直接的流水线实现方式Stream的执行机制-for循环也能干的事Stream的执行机制-基本类图Stream的执行机制-记…

短视频矩阵系统--抖去推---年后技术还能迭代更新开发运营吗?

短视频矩阵系统#短视频矩阵系统已经开发3年&#xff0c;年后这个市场还能继续搞吗&#xff1f;目前市面上开发短视频账号矩阵系统的源头公司已经不多了吧&#xff0c;或者说都已经被市场被官方平台的政策影响的不做了吧&#xff0c;做了3年多的矩阵系统开发到现在真的是心里没有…

Vue2:路由history模式的项目部署后页面刷新404问题处理

一、问题描述 我们把Vue项目的路由模式&#xff0c;设置成history 然后&#xff0c;build 并把dist中的代码部署到nodeexpress服务中 访问页面后&#xff0c;刷新页面报404问题 二、原因分析 server.js文件 会发现&#xff0c;文件中配置的路径没有Vue项目中对应的路径 所以…

python报名人数 2023年9月青少年编程电子学会python编程等级考试二级真题解析

目录 python报名人数 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python报名人数 2023年9月 python编程等级考试级编程题 一、题目要求 1…

20240301-1-ZooKeeper面试题(一)

1. ZooKeeper 面试题&#xff1f; ZooKeeper 是一个开放源码的分布式协调服务&#xff0c;它是集群的管理者&#xff0c;监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终&#xff0c;将简单易用的接口和性能高效、功能稳定的系统提供给用户。 分布式应…

专家揭密,OLED透明屏原的原理

OLED透明屏的原理主要基于OLED&#xff08;有机发光二极管&#xff09;的发光特性。这种屏幕使用透明的电极和有机材料层&#xff0c;通过电流激发有机材料层中的载流子&#xff0c;使其进入发光材料并发生电荷复合&#xff0c;从而释放出光能。 具体来说&#xff0c;OLED透明屏…
最新文章