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

这篇具有很好参考价值的文章主要介绍了c语言结构体看这篇文章就够啦(详细介绍结构体)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

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

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

结构体变量思维导图,c语言的学习,c语言,数据结构

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

思维导图:

结构体变量思维导图,c语言的学习,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的地址:结构体变量思维导图,c语言的学习,c语言,数据结构

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

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:

结构体变量思维导图,c语言的学习,c语言,数据结构

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


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

这里我们打印结果可以证明内存对齐存在结构体变量思维导图,c语言的学习,c语言,数据结构

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;

总结:

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

 最后小马码文不易,如果觉得有帮助就多多支持哈!!!^ _ ^文章来源地址https://www.toymoban.com/news/detail-781981.html

到了这里,关于c语言结构体看这篇文章就够啦(详细介绍结构体)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 学java注解,看这一篇文章就够了

    Annotation(注解)是一种标记,使类或接口附加额外信息,帮助编译器和 JVM 完成一些特定功能。 Annotation(注解)也被称为元数据(Metadata)是JDK1.5及以后版本引入的,用于修饰 包、类、接口、字段、方法参数、局部变量 等。 常见的注解如:@Override、@Deprecated和@SuppressWarnings 2.1 使用步

    2024年02月06日
    浏览(47)
  • DevOps是什么?只看这篇文章就够了!

    作者:沈洲 原文链接:DevOps是什么?只看这篇文章就够了!-云社区-华为云 作为一个热门的概念,DevOps这个名词在程序员社区里频频出现,备受技术大佬们的追捧。甚至网络上有了“南无DevOps”的戏言(南无在梵语的意思是“皈依”),也侧面反映了DevOps的风靡。 然而,一

    2024年02月21日
    浏览(49)
  • tmux 使用看这一篇文章就够了

    tmux是一个终端复用工具,允许用户在一个终端会话中同时管理多个终端窗口,提高了终端使用效率,尤其在服务器上进行远程管理时更加实用。在tmux中,可以创建多个终端窗口和窗格,并在这些窗口和窗格之间自由切换,还可以在后台运行会话,即使在终端断开连接后也可

    2024年02月02日
    浏览(58)
  • JavaWeb入门看这一篇文章就够了

    第1节 什么是web 第2节 什么是JavaWeb   第1节 JavaWeb服务器是什么 第2节 常见的JavaWeb服务器介绍 Tomcat当前最流行的web容器(免费) jetty(免费) Weblogic(收费) 第3节 Tomcat服务器 tomcat服务器介绍 tomcat的目录结构   tomcat的常用命令 tomcat的用户管理 tomcat的服务配置管理 在一台服务器上配

    2024年02月03日
    浏览(65)
  • 关于电脑屏幕亮度的调整,看这篇文章就够了

    你可能需要定期更改屏幕亮度。当外面很亮的时候,你想把它调大,这样你就能看到。当你在黑暗的房间里时,你会希望它变暗,这样就不会伤害你的眼睛。降低屏幕亮度也有助于节省电力并延长笔记本电脑的电池寿命。 除了手动更改屏幕亮度外,Windows还可以通过多种方式

    2024年01月16日
    浏览(45)
  • 【爬虫】最全!selenium和pyppeteer看这一篇文章就够

    目录 摘要: 思路: 区别: 一、selenium 简介 1.1、元素定位 1.2、属性选择器 1.3、定位方式选择 二、Pyppeteer简介 2.1、安装模块 2.2、等待机制和浏览器实例 2.3、常用的页面操作 执行js 元素操作 鼠标事件 键盘事件 内嵌框架 2.4、使用思路和案例 三、BeautifulSoup简介 3.1、安装模块

    2024年02月06日
    浏览(78)
  • 初级面试问到rabbitMQ,看这一篇文章就够了!

    一、rabbitMQ的基础要点回顾 1.使用场景 1) 解耦: 使用消息队列避免模块间的直接调用。将所需共享的数据放在消息队列中,对于新增的业务模块,只要对该类消息感兴趣就可以订阅该消息,对原有系统无影响,降低了各个模块的耦合度,提供系统的扩展性。 2) 异步: 消息

    2024年02月04日
    浏览(52)
  • 交换机如何隔离广播域?(看这篇文章就够了)

         交换机可以隔离冲突域但是不能隔离广播域,当主机数目较多时会导致安全隐患、广播泛滥、性能显著下降甚至造成网络不可用。在这种情况下出现了VLAN (虚拟局域网,Virtual Local Area Network)技术解决以上问题。       如图是一个典型的交换网络,网络中只有终端计算

    2024年02月10日
    浏览(50)
  • 关于HDMI如何连接显示器,看这篇文章就够了

    使用HDMI(高清多媒体接口)电缆将显示器连接到计算机,可以提供一种简单方便的方式来增强你的观看体验。HDMI是一种广泛使用的数字视频和音频接口,可实现视频和音频信号的高质量未压缩传输。使用HDMI,你可以在显示器上享受令人惊叹的视觉效果和水晶般清晰的声音,

    2024年02月01日
    浏览(93)
  • 干货|工作中要使用Git,看这篇文章就够了

    本文将从 Git 入门到进阶、由浅入深,从常用命令、分支管理、提交规范、vim 基本操作、进阶命令、冲突预防、冲突处理等多方面展开,足以轻松应对工作中遇到的各种疑难杂症,如果觉得有所帮助,还望看官高抬贵手给个赞呗,感谢! 虽说现在工作中使用 Git 都会用一些图

    2023年04月25日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包