结构体

结构体在C语言中识非常重要的知识,想要学好C语言就必须学好结构体,那么什么是结构体呢?结构体是一些值的集合,这些值称为成员变量,而结构体的每个成员可以是不同类型的变量;

一、结构体的声明:

1.规规矩矩的结构体类型:

struct tag
{member-list;
}variable-list;

struct是关键字;tag标签名;member-list是成员变量;variable-list是结构体变量名;

创建一个结构体类型:

struct Book
{char name[20];int price;char id[12];
};

注意:在创建结构体的时候;一定不能丢了;

2.特殊的结构体类型:

匿名结构体:

特殊的结构体就是在创建结构体时,省略了结构体的标签,即不完全声明;

看代码说话:

//匿名结构体类型
struct
{int a;char b;float c;
}x;
struct
{int a;char b;float c;
}a[20], *p;
//正常的结构体
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢
//匿名结构体类型
struct
{char c;int i;char b;
}s1;
struct
{char c;int i;char b;
}*ps;
int main()
{ps=&s;//err不合法;return 0;
}
//虽然两个结构体的成员都相同,但是站在编译器的角度,将着两个匿名结构体当作两个不同的变量;

注意:匿名结构体只能用一次,第二次以后引用时编译器就不知道如何去引用,程序就会就会报错;匿名结构体是一次性变量;

二、结构体的自引用:

若结构体变量想要自己引用自己改如何做呢?

是这种形式吗?

struct Node
{
int data;
struct Node next;
};

那如果是这种结构体的大小改怎么来定呢,成员中struct Node next的大小又该是多少呢?显然这种是不合适的;

正确的自引用方式:

struct Node
{
int data;
struct Node* next;//将结构体的地址当做成员变量而不是直接引用结构体;
};

以这种形式进行自引用那么匿名结构体肯定不能进行自引用;
注意注意:

//类型重定义时的结构体自引用要注意的点:
typedef struct
{
int data;
Node* next;
}Node;
//这样写代码肯定是不行的,因为在自引用时Node的类型还未重定义呢,编译器是不知道Node是什么类型;下面这种方法才是正确的://解决方案:
typedef struct Node
{
int data;
struct Node* next;
}Node;

三、结构体变量的定义和初始化:

1.创建结构体的同时定义结构体变量:

struct Point
{
int x;
int y;
}p1; //声明类型的同时定义变量p1

2.创建了结构体之后定义结构体变量:

struct Point
{
int x;
int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2

3.结构体的初始化:

#include <stdio.h>
struct S1
{char i;int a;int b;
}s1;//创建结构体的同时创建结构体变量;
struct S2
{char i;int d;struct S1 s;
};
int main()
{struct S1 s2 = { 'w',10,20};//创建结构体的变量后初始化结构体变量;struct S1 s3 = { .b = 20,.i = 'm',.a = 30 };//按指定的顺序初始化结构体变量;struct S2 s4 = { 'q',50,{'z',15,25} };//初始化嵌套结构体变量的结构体;
}

四、结构体内存对齐:

结构体内存对齐是结构体中超级超级重要的知识(计算结构体的大小是一个热门考点)!!!

1.首先我们要知道为什么存在内存对齐:

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

2.结构体的对齐规则:

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

可能上面的对齐规则规则会看不懂,我根据自己的所学总结了简单易懂的对齐法则:结构体的大小可以理解为:我这里所说的最大对齐数是成员中基本类型(char、short、int、long long、float、double)大小最大的类型的字节数的每个成员要凑够最大对齐数量的空间,实际字节数超过最大对齐数的凑够最大对齐数的最小整数倍;若相邻的两个成员实际字节数都小于最大字节数则将两者相加后的字节数是最大字节数的最小整数倍就可以,结构体的大小就是特们的总和,当结构体中嵌套结构体并且嵌套的结构体的大小比8大时则最大对齐数就是默认对齐数8;

上代码:

struct S1
{char c1;int i;char c2;
}s1;//最大的对齐数是4,c1不够4字节我们需要浪费3个字节凑够4字节,i是4字节不需要拼凑,c2不够4字节我们也需要浪费3个字节凑够4字节,那么总共就是12字节
struct S2
{char c1;char c2;int i;
}s2;//最大的对齐数是4,c1和c2是相邻两个成员而且实际字节数都小于最大对齐数,那么将两者的实际字节数相加看是否等于最大对齐数或最大对齐数的最小整数倍,不够的凑够相应的字节数,则就是4字节,i是4字节不需要拼凑,那么大小就是8字节;
struct S3
{double d;char c;int i;
}s3;//最大的对齐数是8,d是8字节不需要拼凑,c和i相邻而且实际字节数都小于最大的对齐数是8,那么就将两者实际字节数相加为5,不够8字节需要我们浪费3字节凑够8字节,那么大小就是16;
struct S4
{char c1;struct S3 s3;double d;
}s4;//最大的对齐数为8,c1不够8字节我们需要浪费7个字节凑够8字节,嵌套的结构体的大小上面中我们计算为16字节,正好是8的倍数,d是8字节也不需要拼凑,那么结构体s4的大小就是32;int main()
{printf("%d\n", sizeof(struct S1));printf("%d\n", sizeof(struct S2));printf("%d\n", sizeof(struct S3));printf("%d\n", sizeof(struct S4));return 0;
}

运行结果:

 3.修改默认对齐数:

之前我们见过了 #pragma 这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数。

#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
//输出的结果是什么?
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}

结论:
结构在对齐方式不合适的时候,我么可以自己更改默认对齐数。

五、结构体传参:

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); //传地址:属于址传递,在空间和时间上都会节省,想要该变结构体也不会受到限制,若不想改变结构体时只要在前面加上const即可:
return 0;
}

所以以后在传递结构体变量时尽量使用传地址的方式;

以上就是结构体的部分内容,愿喜欢编程的朋友一起进步!!!!!!!

看这里看这里:结构体的超级详细讲解相关推荐

  1. C语言qsort()函数针对:整型、单个字符、字符串、结构体,超详细讲解(多维度分析举例,小白一看就懂!!!!!)

    目录 一.前言 二.qsort()函数

  2. 串口初始化结构体和固件库讲解

    串口初始化结构体和固件库讲解 常用的6个函数,结构体: USART 初始化结构体(USART_InitTypeDef) USART 时钟初始化结构体(USART_ClockInitTypeDef) 串 ...

  3. C语言结构体——位段概念的讲解

    前言 之前我对结构体内存分配的方式.对默认对齐数的指令修改做了详细的博客讲解,(C语言结构体详解 (2) 结构体内存对齐,默认对齐数,大家有兴趣的话可以去了解了解这方面的知识. 一. 什么是位段? 位 ...

  4. 宽度优先搜索算法(BFS)详解(超级详细讲解,附有大图)

    目录 一.宽度优先搜索(BFS)是什么? 二.图解宽搜(BFS) 三.对比与发现 四.工具--队列 五.模板 六.最后 一.宽度优先搜索(BFS)是什么? 百度百科这样说: 宽度优先搜索算法(又称广度 ...

  5. 看电影(C++结构体练习题)

    [问题描述] 某大学正在举办一场重要的国际学术会议,出席会议的 n 位科学家来自不同的国家,每位科学家都只熟悉一种语言,为方便起见,世界上所有的语言用1~1000的数字编号来列出. 晚上,主办方安排所 ...

  6. 『数据库』震惊,某博主为吸引眼球拿出压箱底SQL总结,如果你没看那就吃亏了!(超级详细的SQL基础,你还不会的话就别学数据库了)

    这里还有数据库相关的优质文章:快戳我,快戳我

  7. QT入门看这一篇就够了——超详细讲解(40000多字详细讲解,涵盖qt大量知识)

    目录 一.Qt概述 1.1 什么是Qt 1.2 Qt的发展史 1.3 Qt的优势 1.4 Qt版本 1.5 成功案例 二.创建Qt项目 2.1 使用向导创建 2.2 一个最简单的Qt应用程序 2.2. ...

  8. 串口编程DCB结构体参数配置详细说明

    序号 字段 释义 1 DWORD DCBlength.: sizeof(DCB) 2 DWORD BaudRate; current baud rale指定当前的波特率 3 DWORD fBinary ...

  9. openlaw爬虫超级详细讲解

    openlaw爬虫 openlaw网站有严格加密,代码可以运行,但是如果想获取太多数据建议根据官网要求来 1.openlaw内容页超链接加密 打开openlaw网站搜索刑事,打开检查,看见超链接是加密 ...

最新文章

  1. Datagridview 在基于文本的单元格中启用换行,自动调整行高列宽
  2. 高会的计算机模块,2017高会《职称计算机》模块精讲:写字板和便笺
  3. 拖动效果,防止选中文字兼容代码
  4. 使用Spring Integration聚合异步结果
  5. Docker垃圾清理方案
  6. SVN使用教程总结[转]
  7. 【推荐实践】深度学习在阿里B2B电商推荐系统中的实践
  8. 让Cocos2dx中的TestCPP中的Box2dTest运行起来
  9. AI数学手册:线性代数、拓扑、微积分和最优化 | 资料
  10. 【命令行】CMD/BAT文件执行时中文乱码的解决方法
  11. C1驾考 科目二 (超详细!文字+实拍图)
  12. 工业可视化三维建模数据3d可视化平台
  13. L2行情接口怎么用最高效?
  14. html5 手机号直接拨打,html5拨打电话及发短信
  15. [系统安全] 五.OllyDbg和Cheat Engine工具逆向分析植物大战僵尸游戏
  16. 怎么把微信公众号的文章里的音频或视频下载到电脑和手机
  17. Web防火墙(WAF)是什么?和传统防火墙区别是什么?
  18. 枚举类型是什么意思,怎么用?
  19. 华为云发布桌面IDE-CodeArts
  20. iOS8扩展插件开发配置

热门文章

  1. 2022 CCPC 威海 赛后总结
  2. oracle--dump 块与块分析 (dump 深入实践二)
  3. 静态库和动态库的调用
  4. 用C语言实现控制台播放音乐的功能
  5. 猪齿鱼V2.1.0 发布 移动办公、知识在线协作, 项目管理快人一步
  6. 你有22款高逼格免费字体请下载!
  7. 奔向光明阿波罗(上)
  8. linux下修改或删除包含乱码、特殊符号等文件名的文件
  9. javascript字符串分割为数组
  10. allegro学习之总结pcb设计流程