c语言结构体看这篇文章就够啦(详细介绍结构体)

news2024/11/17 9:35:10

前言:

        c语言两大重要点,一个是指针,另一个就是结构体啦,这篇文章我将全面的介绍一下结构体,和他的使用,相信大家看完这篇以后定能对结构体有个深入的理解,并且会正确的使用它。

 💞 💞    欢迎来到小马学习代码博客!!!

 现在已经入冬了吧,小马想问一下大家那里都下雪了嘛,我们这还没有下,但是在家里真的好冷啊,根本不想出门😭 

思维导图:

 

 

目录

一、结构体的认识

1.1结构体存在的意义:

1.2结构体的声明和定义:

1.3结构体的特殊声明:

1.4结构体的访问:

1.5结构体的初始化:

1.6结构体的传参:

2、结构体内存对齐

2.1结构体对齐的意义:

2.2结构体内存对齐的规则:

2.3代码演示:

2.4默认对齐数的修改: 

3、结构体类型

3.1结构体数组:

3.2结构体指针:

总结:


 

一、结构体的认识

1.1结构体存在的意义:

         结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
要知道数组存放的是相同类型的数据,而在日常生活中描述一个东西就不能用单单一个数据,例如描述一个学生,则需要姓名,性别,年龄,身高等等,这些就里就不能用数组来实现,固然需要我们用到结构体来完成。 结构体不仅可以记录不同类型的数据,而且使得数据结构是“高内聚,低耦合”的,更利于程序的阅读理解和移植,而且结构体的存储方式可以提高CPU对内存的访问速度。

1.2结构体的声明和定义:

struct tag
{
member-list;
 }variable-list;
例如一个学生的信息:
1.2.1声明了之后定义
struct Student
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢

struct Student stu1; //定义结构体变量

1.2.2声明的同时直接定义

struct Student
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}stu1; //分号不能丢 //声明的同时定义

1.3结构体的特殊声明:

//匿名结构体类型
struct
{
int a;
char b;
float c; 
}x;

匿名结构体类型不好的一点就是定义之后不能在定义新的结构体变量了。

1.4结构体的访问:

        在数组中我们是通过数组的下标来访问的,但是在结构体中,每个元素的类型都不是相同的,所以没办办法通过下表的方式来进行访问,故通过结构变量的成员是通过点操作符(.)访问的。

例如:

struct Student
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}stu1; //分号不能丢

stu1.name 表示这个学生的姓名,stu1.age表示这个学生的年龄等等。

要是结构体里面嵌套一个结构体:

struct Birthday{
    int year;
    int month;
    int day;
};
struct Student{
    char name[20];
    int age ;
    char sex[20];
    char id[20];
    struct Birthday birthday;
}stu1;

stu1.name.month 表示这个学生的生日的月份,stu1.name.year 表示生日的年份

结构体指针访问指向变量的成员
struct Stu
{
char name[20];
int age;
};

void print(struct Stu* ps) {
printf("name = %s   age = %d\n", (*ps).name, (*ps).age);
    //使用结构体指针访问指向对象的成员
printf("name = %s   age = %d\n", ps->name, ps->age);
}
int main()
{
    struct Stu s = {"zhangsan", 20}; //结构体的赋值
    print(&s);//结构体地址传参
    return 0;
 }

这里是通过箭头来访问的

1.5结构体的初始化:

1.5.1在定义后在进行成员逐步赋值:

struct Student
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢

int main()
{
    struct Student stu1;
    strcpy(stu1.name,"xiaoma"); //strcpy进行赋值
    stu1.age =18;
    strcpy(stu1.sex,"nan");
    strcpy(stu1.id,"12345667");
    
}

1.5.2在定义后进行整体赋值:

struct Student{
    char name[20];
    int age ;
    char sex[20];
    char id[20];
};
int main()
{
    
    struct Student stu2;
    stu2=(struct Student){"xiaoli",18,"nan","1234567"};
    //这里要进行强制类型转换 因为数组的赋值也是用的{},你要把它转换为结构体的赋值
    
}

1.5.3在定义的同时进行整体赋值 :

struct Student{
    char name[20];
    int age ;
    char sex[20];
    char id[20];
}stu1={"xiaoma",18,"nan","12345667"};  //这是一种定义的同时进行赋值
int main()
{
    
    struct Student stu2={"xiaoli",18,"nan","1234567"};  //这是第二种定义后同时进行赋值
}
//要注意赋值的顺序要和你声明的元素顺行相同

1.5.4在定义的同时进行部分赋值:

struct Student{
    char name[20];
    int age ;
    char sex[20];
    char id[20];
}stu1={.name="xiaoma"};
int main()
{
    
    struct Student stu2={.name="xiaoli"}; //这里只是给姓名进行赋值

}

1.5.5通过结构体进行赋值:

struct Student{
    char name[20];
    int age ;
    char sex[20];
    char id[20];
}stu1={.name="xiaoma"};
int main()
{
    
    struct Student stu2={.name="xiaoli"};
    stu2=stu1;
    
}

这里是把结构体stu1赋值给结构体stu2(这里只是成员间进行赋值,并不改变结构体的地址

我们分别打印一下结构体的stu1和结构体stu2的地址:

发现只是将值进行的赋值,但地址并没有进行改变 。

1.6结构体的传参:

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; }

这里我们有两种传参方法,一种是进行整体结构体传参,另一个是进行地址传参,这两种哪一种比较好呢?传地址是比较好的 因为:函数传参的时候,参数是需要压栈的。 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。

2、结构体内存对齐

2.1结构体对齐的意义:

      内存是以字节为单位编号的,某些硬件平台对特定类型的数据的内存要求从特定的地址开始,如果数据的存放不符合其平台的要求,就会影响到访问效率。所以在内存中各类型的数据按照一定的规则在内存中存放,就是对齐问题。而结构体所占用的内存空间就是每个成员对齐后存放时所占用的字节数之和。

1. 平台原因(移植原因)

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特

定类型的数据,否则抛出硬件异常。
 
2. 性能原因
数据结构 ( 尤其是栈 ) 应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
问。
总体来说:
结构体的内存对齐是拿空间来换取时间的做法。

2.2结构体内存对齐的规则:

1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

对齐数:在编译器中都存在一个默认对齐数 VS编译器的对齐数是8 成员大小就是所占字节的大小例如 int的是4,char是1等等

2.3代码演示:

struct S1
{
char c1;
int i;
char c2;
};
int main()
{
    printf("%lu\n", sizeof(struct S1));
    return 0;
    
}

例如这个结构体 我们算的他所占字节是12 而结构体S1中就一个两个char类型和一个int类型不应该字节数为6吗 这里就是因为结构体内存对齐。

这里解释了为什么是12:

我们也可以进行对偏移量的打印来确认一下


#include<stdio.h>
#include<stddef.h>  //运用offsetof这个宏需要引用这个头文件
struct S1
{
char c1;
int i;
char c2;
   
};
int main()
{
    printf("%lu\n", sizeof(struct S1));
    printf("%lu\n",offsetof(struct S1,c1));
    printf("%lu\n",offsetof(struct S1,i));
    printf("%lu\n",offsetof(struct S1,c2));
    
    return 0;
    
}

这里我们打印结果可以证明内存对齐存在

2.4默认对齐数的修改: 

#pragma pack(4)     //这里把默认对齐数修改成了4
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()     //这里又回到了最初的默认对齐数

3、结构体类型

3.1结构体数组:

   结构体数组一般应用还比较多 例如:在完成通讯录的时候,一个人员信息用结构体但通讯录并不是一个成员,则需要应用到结构体数组,在进行同学信息统计也需要应用结构体数组。结构体数组的定义和初始化其实都和上面差不多

3.1.1进行声明的同时定义:

struct Student
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}stu[5]; //分号不能丢

3.1.2声明后定义:

struct Student
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢

struct Student stu[5];

3.1.3定义结构体数组同时进行初始化:

struct Student
{
char name[20];//名字
int age;//年龄
}; //分号不能丢

struct Student stu[2]={{"xiaoma",18},{"xiaoli",18};

3.1.4定义后在进行初始化:

struct Student
{
char name[20];//名字
int age;//年龄
}; //分号不能丢

struct Student stu[2];
stu[1]=(struct Student){"xiaoma",18};

3.1.5将每个成员逐步初始化:

struct Student
{
char name[20];//名字
int age;//年龄
}; //分号不能丢

struct Student stu[2];
strcpy(stu[2].name,"xiaoma");
stu[2].age=18;

3.2结构体指针:

结构体指针应用在数据结构中比较多:例如应用在单链表,带头双向循环链表中用来指向下一个结构体,同时进行结构体传参的时候运用指针也比较好。例子我就不举了,大家可以看一下我的单向循环链表,和带头双向循环链表进行深入的了解一下结构体指针。

struct Student
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢

struct Student *pstu;

总结:

        以上就是结构体的全部内容了,从结构体的认识,结构体存在的意义是什么,他和数组的区别,同时也有结构体的声明定义和初始化,在之后也讲述了结构体内存对齐的原理和为什么要进行内存对齐,在之后结构体类型中只是讲述了结构体数组,和结构体指针,结构体函数传参(在上面),结构体传参为什么有地址进行传参,而不是整体的进行传他的好处,这里已经尽小马所能把结构体能想到的都给大家全部呈现出来啦!

 最后小马码文不易,如果觉得有帮助就多多支持哈!!!^ _ ^

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智工教育:注册计量师一级和二级的科目一样吗?

注册计量师有二级、一级之分&#xff0c;其中二级考试所涉及的科目为《计量法律法规及综合知识》《计量专业实务与案例分析》&#xff0c;必须要在连续2年内考过&#xff0c;否则就要重新报考。 而一级的考试科目&#xff0c;则分别是《计量法律法规及综合知识》、《测量数据处…

H2/H∞半车悬架控制仿真分析

目录 前言 1.悬架模型 2.LMI求解 3.simulink仿真分析 3.1结论 前言 对于H2/H∞控制的鲁棒项相比不用多说&#xff0c;之前也写过两篇关于1/4车的H2/H∞控制文章&#xff0c;链接如下&#xff1a; 基于LMI的车辆主动悬架控制_Mr. 邹的博客-CSDN博客 基于MATLAB/Simulink的…

01-redis篇 两种数据储存持久化方式

目录 1. 背景: 2. 两种数据持久化方式 2.1 RDB存储机制 -> (1) 配置docker版redis -> (2) rdb默认开启, 配置如下 redis.conf 打开 ->(3)安全退出的模式 ->(4) save与bgsave 2.2 AOF持久化机制 ->(1) 修改redis.conf 开启aof储存机制 ->(2) 为什么要…

ahooks解决React闭包问题方法示例

这篇文章主要为大家介绍了ahooks解决React闭包问题方法示例详解&#xff0c;有需要的朋友可以借鉴参考下&#xff0c;希望能够有所帮助&#xff0c;祝大家多多进步&#xff0c;早日升职加薪 引言 本文是深入浅出 ahooks 源码系列文章的第三篇&#xff0c;这个系列的目标主要有…

ShardingSphere介绍

ShardingSphere产品介绍 Apache ShardingSphere 是一款分布式的数据库生态系统&#xff0c; 可以将任意数据库转换为分布式数据库&#xff0c;并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。 设计哲学为 Database Plus&#xff0c;旨在构建异构数据库上层的标准…

项目管理逻辑:为什么职能部门官僚主义气息浓重?

目录 1.管理孤岛 2.业务部门和职能部门之间的关系 3.企业如何转型升级 3.1垂直管理模式 3.2精细管理模式 4.成熟企业的职能部门和组织部门 1.管理孤岛 职能部门办事状态 每个公司通常从管理的角度会划分很多个层级 . 不同层级之间通常会存在管理隔阂,也就是说不同的领…

HCIA笔记(2)

一、地址&#xff08;全球唯一、地址统一&#xff09; 1.MAC地址&#xff1a;芯片出厂时&#xff0c;厂家烧录进去的一个串号。48位二进制构成 2.物理地址&#xff1a;C8-CB-9E-6B-3A-41 --- 为了方便人类区分和识别&#xff0c;我们会将48位二进制转换为12位16进制表示 3.查…

logging java日志选择

文章目录hutoolsslf4japache logging[JDK logging](https://www.liaoxuefeng.com/wiki/1252599548343744/1264738568571776)logbacklog4j2hutools <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>…

一种在 Python 中实现更快 OpenCV 视频流的多线程方法

概述在本文中&#xff0c;我们将看到两个没有多线程的 Python 代码示例&#xff0c;用于从摄像头读取视频帧。我们将看到使用/不使用多线程获得的 FPS 的差异。什么是多线程&#xff1f;线程是进程中的一个执行单元。多线程是指通过在线程之间快速切换对 CPU 的控制&#xff08…

257.二叉树的所有路径

257.二叉树的所有路径 文章目录257.二叉树的所有路径题目题解技巧 - 参数的作用域巧妙的题解方法题目 给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&a…

【Redis实战】GeoHash实现原理与基本使用

文章目录GeoHash可以解决什么问题&#xff1f;基于网格划分的最近邻查询GeoHash划分规则GeoHash的使用方式Redis GEOADD 命令语法示例Redis GEORADIUS 命令语法半径单位&#xff1a;可选性参数&#xff1a;示例Redis GEORADIUSBYMEMBER 命令语法示例Redis GEODIST 命令语法示例…

Android 面试中Binder必问,是否了解过?

1.简单介绍下binder binder是一种进程间通讯的机制 进程间通讯需要了解用户空间和内核空间 每个进程拥有自己的独立虚拟机&#xff0c;系统为他们分配的地址空间都是互相隔离的。 如两个进程需要进行通讯&#xff0c;则需要使用到内核空间做载体&#xff0c;内核空间是所有进…

GPS卫星位置解算

本文介绍了基于C语言的GPS卫星位置解算原理与程序设计。针对每个原理、公式、代码设计进行了详细讲解&#xff0c;希望能够给测绘学子们带来帮助。 参考书籍&#xff1a; 李征航 黄劲松&#xff1a;GPS测量与数据处理&#xff08;第三版&#xff09; 目录 基础原理 1&#xf…

Spring框架(十一):手动实现一个@Component,讲一讲Spring的工厂后处理器

手动实现一个Component&#xff0c;讲一讲Spring的工厂后处理器引子需求代码分析Spring工厂后处理器引子 痛定思痛&#xff0c;主要问题出现在自己雀氏不熟悉框架底层、一些面试题&#xff0c;以及sql的一些情况淡忘了。 本章节的开始是对于过去的重新回顾&#xff0c;当然&am…

【AI】Python 实现八数码问题

实验一 八数码问题 1. 题目介绍 八数码问题描述为&#xff1a;在 33 组成的九宫格棋盘上&#xff0c;摆有 8 张牌&#xff0c;每张牌都刻有 1-8 中的某一个数码。棋盘中留有一个空格&#xff0c;允许其周围的某张牌向空格移动&#xff0c;这样通过移动牌就可以不断改变棋盘布…

PDF或PPT中的某个图或表无损、高清的插入word里的方法,再转成pdf后放大6400%倍仍是高清图片...

本人使用Microsoft Office LTSC 专业增强版 2021版本的&#xff0c;其他版本不确定可不可以 可通过office tool plus下载安装相应版本的office&#xff0c;通过安装与激活安装与激活 0. 参考方法网址&#xff1a; PDF 转成 SVG 格式的方法(无损保留笔记痕迹) 1. pdf可能很多页&…

Dubbo SPI扩展机制源码详解(基于2.7.10)

Dubbo SPI 一. 概述 本文主要分享 Dubbo 的拓展机制 SPI。 想要理解 Dubbo &#xff0c;理解 Dubbo SPI 是非常必须的。在 Dubbo 中&#xff0c;提供了大量的拓展点&#xff0c;基于 Dubbo SPI 机制加载 Dubbo SPI官方文档&#xff1a;Dubbo SPI 概述 | Apache Dubbo 本文基…

Spring-IOC控制反转

Spring 1.简介 1.1简介 1.常见的框架&#xff1a; 2.常见的依赖&#xff1a; <dependencies><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artif…

SpringBoot基础之声明式事务和切面事务和编程式事务

文章目录前言一、事务特性开启事务二、事务的隔离级别三、事务的传播行为四、 Springboot事务1.Springboot声明式事务优点&#xff1a;缺点&#xff1a;实现方式&#xff1a;Transactional的参数声明式事务的约定流程&#xff1a;2. Springboot编程式事务SpringBoo切面编程式事…

[附源码]Python计算机毕业设计SSM教学团队管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…