从浅入深掌握进阶结构体(C语言)

2023-12-09 00:01

本文主要是介绍从浅入深掌握进阶结构体(C语言),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言
这一期我们将继续讲解结构体的知识,还没有看过上一期的小伙伴一定要赶紧去学习哦。
上一期,冲鸭!
那么话不多说我们开始今天的学习吧!
在这里插入图片描述

文章目录

  • 1,结构体的自引用
  • 2,匿名结构体
  • 3,位段
  • 4,结构体的传参
  • 5,尾声

1,结构体的自引用

什么是结构体的自引用呢?简单来说就是自己装自己(有点类似递归)。
那么是这样自引用的么?

struct student
{
char name[20];
int age;
float score;
struct student next_student;//这是我们自己定义的一个类型的解耦提变量如果可以这样写,我们就可以在一个学生的结构体里包含下一个学生的结构体,如果有一百个学生,我们就可以通过第一个学生访问到第一百个学生
}stu1;

但是这样写好像有问题啊,我们刚学过内存对齐的知识,在编译期间,编译器需要知道结构体变量大小为结构体变量分配空间,可是这个好像没法知道这个结构体变量的大小是多少,会陷入无限的递归之中。那我们是不是可以换个思路呢?我们不是在结构体成员中加入下一个学生的结构体变量,而是加入下一个学生的结构体变量的地址不就可以了么,这样就不会陷入无限的递归之中。而且我们能通过地址寻找到下一个学生的信息。书写方式如下:

struct student
{
char name[20];
int age;
float score;
struct student* next_student;//储存下一个学生(结构体变量)的地址
}stu1;

2,匿名结构体

匿名结构体是什么呢?就拿我们刚才创建了类型为为student的结构体。如果我们这样写代码呢?

struct 
{
char name[20];
int age;
float score;
}stu1;

是不是发现少了student,这种特殊的声明我们就称之为匿名结构体。
但是需注意的是匿名结构体的变量只能在声明时创建且只能有一个变量。也就是说只能使用一次,我们不能对匿名结构体自引用。

3,位段

学习位段之前我们先看如下代码。

struct student
{
char name[20];
int age:6;
int score:8;
}

我们发现该结构体的成员中年龄和分数后面多了一个:和一个数字,这是代表什么意思呢?正常情况下,一个学生的年龄应该在6-31岁之间,因为年龄是个整形数据,所以会给它分配4个字节大小的空间,但是如果只要表达0-31这些数字的话完全不需要那么大的空间对于有符号整形来说只需要6个bit位就足够了,那么回到代码,int age:6;的意思就是给这个整形分配6个比特的空间。而score给他分配了8个字节的空间。那么这个时结构体的内存是如何分配的呢?

struct uma
{
int a:2;
int b:3;
int c:5;
int d:10;

以这个结构体为例。
在这里插入图片描述
相比通过这张图片就能够了解位段是如何分配空间的了。
但是我们还需注意以下几点。
1, 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以 选择其他类型。
2, 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使⽤位段。

4,结构体的传参

在函数中我们该怎么对结构体进行传参呢?
我们有以下两种方法

#include <stdio.h>
struct Student
{int data[1000];int num;
};
struct Student s = { {1,2,3,4}, 1000 };
//结构体传参
void print1(struct Student s)
{printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct Student* ps)
{printf("%d\n", ps->num);
}
int main()
{print1(s); //传结构体print2(&s); //传结构体的地址return 0;
}

那么这两种写法哪种更好呢?没错就是第二种,因为直接传递结构体的话,计算机会给形参重新开辟一块内存空间,小的还好说,要是特别大的结构体那么会相当的浪费内存,而传递地址就不一样了并不需要重新开辟一片空间,可以提升程序的性能。

5,尾声

学习完这两篇博客的小伙伴想必已经非常了解了结构体的用法,但是也要多加练习哦正所谓熟能生巧,下次我将找几道结构体的题目来跟大家分享一下。结构体习题链接,gogogo!
如果觉得博主讲的不错的千万不要忘记关注博主哦,你们的关注我是最大的动力!

这篇关于从浅入深掌握进阶结构体(C语言)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/471775

相关文章

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五

Oracle查询表结构建表语句索引等方式

《Oracle查询表结构建表语句索引等方式》使用USER_TAB_COLUMNS查询表结构可避免系统隐藏字段(如LISTUSER的CLOB与VARCHAR2同名字段),这些字段可能为dbms_lob.... 目录oracle查询表结构建表语句索引1.用“USER_TAB_COLUMNS”查询表结构2.用“a

C语言中%zu的用法解读

《C语言中%zu的用法解读》size_t是无符号整数类型,用于表示对象大小或内存操作结果,%zu是C99标准中专为size_t设计的printf占位符,避免因类型不匹配导致错误,使用%u或%d可能引发... 目录size_t 类型与 %zu 占位符%zu 的用途替代占位符的风险兼容性说明其他相关占位符验证示

C语言进阶(预处理命令详解)

《C语言进阶(预处理命令详解)》文章讲解了宏定义规范、头文件包含方式及条件编译应用,强调带参宏需加括号避免计算错误,头文件应声明函数原型以便主函数调用,条件编译通过宏定义控制代码编译,适用于测试与模块... 目录1.宏定义1.1不带参宏1.2带参宏2.头文件的包含2.1头文件中的内容2.2工程结构3.条件编

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

从入门到进阶讲解Python自动化Playwright实战指南

《从入门到进阶讲解Python自动化Playwright实战指南》Playwright是针对Python语言的纯自动化工具,它可以通过单个API自动执行Chromium,Firefox和WebKit... 目录Playwright 简介核心优势安装步骤观点与案例结合Playwright 核心功能从零开始学习

全面掌握 SQL 中的 DATEDIFF函数及用法最佳实践

《全面掌握SQL中的DATEDIFF函数及用法最佳实践》本文解析DATEDIFF在不同数据库中的差异,强调其边界计算原理,探讨应用场景及陷阱,推荐根据需求选择TIMESTAMPDIFF或inte... 目录1. 核心概念:DATEDIFF 究竟在计算什么?2. 主流数据库中的 DATEDIFF 实现2.1

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化