C语言自学笔记17----结构体struct与位域与关键字typedef

C 语言结构体(struct)
为什么在C中使用结构?
假设您要存储有关一个人的信息:他/她的姓名,身份证号和薪水。您可以创建不同的变量name,citNo和salary存储此信息。
如果您需要存储多个人的信息怎么办?现在,你需要为每个人每个信息创建不同的变量:name1,citNo1,salary1,name2,citNo2,salary2, 等。

在C语言编程中,有时需要存储实体的多个属性。 实体不必仅具有一种类型的所有信息。 它可以具有不同数据类型的不同属性。

C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
定义结构
**为了定义结构,您必须使用 struct 关键词。struct 语句定义了一个包含多个成员的新的数据类型,**struct 语句的格式如下:

struct tag {
member-list
member-list
member-list

} variable-list ;
tag 是结构体标签。

member-list 是标准的变量定义,比如 int i; 或者 float f,或者其他有效的变量定义。
**variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。
**下面是声明 Book 结构的方式:

struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;

struct
{
int a;
char b;
double c;
} s1;
//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//同时又声明了结构体变量s1
//这个结构体并没有标明其标签

struct SIMPLE
{
int a;
char b;
double c;
};

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//结构体的标签被命名为SIMPLE,没有声明变量
*//用SIMPLE标签的结构体,另外声明了变量t1、t2、t3
struct SIMPLE t1, t2[20], t3;

//也可以用typedef创建新类型
typedef struct
{
int a;
char b;
double c;
} Simple2;
//现在可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;

结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。

//此结构体的声明包含了其他的结构体
struct COMPLEX
{
char string[100];
struct SIMPLE a;
};

//此结构体的声明包含了指向自己类型的指针
struct NODE
{
char string[100];
struct NODE *next_node;
};
如果两个结构体互相包含,则需要对其中一个结构体进行不完整声明,如下所示:

struct B; //对结构体B进行不完整声明

//结构体A中包含指向结构体B的指针
struct A
{
struct B *partner;
//other members;
};

//结构体B中包含指向结构体A的指针,在A声明完后,B也随之进行声明
struct B
{
struct A *partner;
//other members;
};
结构体变量的初始化
和其它类型变量一样,对结构体变量可以在定义时指定初始值。

示例
#include <stdio.h>

struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book = {“C 语言”, “nhooo”, “编程语言”, 123456};

int main()
{
printf(“书名: %s\n作者: %s\n主题: %s\nBookID %d\n”, book.title, book.author, book.subject, book.book_id);
}
执行输出结果为:

书名: C 语言
作者: nhooo
主题: 编程语言
BookID 123456
访问结构成员
为了访问结构的成员,我们使用成员访问运算符(.)。成员访问运算符是结构变量名称和我们要访问的结构成员之间的一个句号。您可以使用 struct 关键字来定义结构类型的变量。

#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};

int main( )
{
struct Books Book1; /* 声明 Book1,类型为 Books /
struct Books Book2; /
声明 Book2,类型为 Books */

/* Book1 详述 */
strcpy( Book1.title, “C 编程语言”);
strcpy( Book1.author, “Nuha Ali”);
strcpy( Book1.subject, “C 编程语言教程”);
Book1.book_id = 6495407;

/* Book2 详述 */
strcpy( Book2.title, “JAVA编程语言”);
strcpy( Book2.author, “Seagull Ali”);
strcpy( Book2.subject, “JAVA编程语言教程”);
Book2.book_id = 6495700;

/* 输出 Book1 信息 */
printf( “Book 1 书名: %s\n”, Book1.title);
printf( “Book 1 作者: %s\n”, Book1.author);
printf( “Book 1 主题: %s\n”, Book1.subject);
printf( “Book 1 编号: %d\n”, Book1.book_id);

/* 输出 Book2 信息 */
printf( “Book 2 书名: %s\n”, Book2.title);
printf( “Book 2 作者: %s\n”, Book2.author);
printf( “Book 2 主题: %s\n”, Book2.subject);
printf( “Book 2 编号: %d\n”, Book2.book_id);

return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:

Book 1 书名: C 编程语言
Book 1 作者: Nuha Ali
Book 1 主题: C 编程语言教程
Book 1 编号: 6495407
Book 2 书名: JAVA编程语言
Book 2 作者: Seagull Ali
Book 2 主题: JAVA编程语言教程
Book 2 编号: 6495700
结构作为函数参数
您可以把结构作为函数参数,传参方式与其他类型的变量或指针类似。

#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
/* 函数声明 /
void printBook( struct Books book );
int main( )
{
struct Books Book1; /
声明 Book1,类型为 Books /
struct Books Book2; /
声明 Book2,类型为 Books */

/* Book1 详述 */
strcpy( Book1.title, “C 编程语言”);
strcpy( Book1.author, “Nuha Ali”);
strcpy( Book1.subject, “C 编程语言教程”);
Book1.book_id = 6495407;

/* Book2 详述 */
strcpy( Book2.title, “JAVA编程语言”);
strcpy( Book2.author, “Seagull Ali”);
strcpy( Book2.subject, “JAVA编程语言教程”);
Book2.book_id = 6495700;

/* 输出 Book1 信息 */
printBook( Book1 );

/* 输出 Book2 信息 */
printBook( Book2 );

return 0;
}
void printBook( struct Books book )
{
printf( “Book 书名: %s\n”, book.title);
printf( “Book 作者: %s\n”, book.author);
printf( “Book 主题: %s\n”, book.subject);
printf( “Book 编号: %d\n”, book.book_id);
}
当上面的代码被编译和执行时,它会产生下列结果:

Book 书名: C 编程语言
Book 作者: Nuha Ali
Book 主题: C 编程语言教程
Book 编号: 6495407
Book 书名: JAVA编程语言
Book 作者: Seagull Ali
Book 主题: JAVA编程语言教程
Book 编号: 6495700
*指向结构的指针
您可以定义指向结构的指针,方式与定义指向其他类型变量的指针相
struct Books struct_pointer;

在上述定义的指针变量中存储结构变量的地址。为了查找结构变量的地址,请把 & 运算符放在结构名称的前面,如下所示:

struct_pointer = &Book1;
为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符
struct_pointer->title;

#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};

/* 函数声明 */
void printBook( struct Books book );
int main( )
{
struct Books Book1; /
声明 Book1,类型为 Books /
struct Books Book2; /
声明 Book2,类型为 Books */

/* Book1 详述 */
strcpy( Book1.title, “C 编程语言”);
strcpy( Book1.author, “Nuha Ali”);
strcpy( Book1.subject, “C 编程语言教程”);
Book1.book_id = 6495407;

/* Book2 详述 */
strcpy( Book2.title, “JAVA编程语言”);
strcpy( Book2.author, “Seagull Ali”);
strcpy( Book2.subject, “JAVA编程语言教程”);
Book2.book_id = 6495700;

/* 通过传 Book1 的地址来输出 Book1 信息 */
printBook( &Book1 );

/* 通过传 Book2 的地址来输出 Book2 信息 */
printBook( &Book2 );

return 0;
}
void printBook( struct Books *book )
{
printf( “Book 书名: %s\n”, book->title);
printf( “Book 作者: %s\n”, book->author);
printf( “Book 主题: %s\n”, book->subject);
printf( “Book 编号: %d\n”, book->book_id);
}
当上面的代码被编译和执行时,它会产生下列结果:

Book 书名: C 编程语言
Book 作者: Nuha Ali
Book 主题: C 编程语言教程
Book 编号: 6495407
Book 书名: JAVA编程语言
Book 作者: Seagull Ali
Book 主题: JAVA编程语言教程
Book 编号: 6495700
位域
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。
所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

典型的示例:
用 1 位二进位存放一个开关量时,只有 0 和 1 两种状态。
读取外部文件格式——可以读取非标准的文件格式。例如:9 位的整数。
位域的定义和位域变量的说明
位域定义与结构定义相仿,其形式为:
struct 位域结构名
{
位域列表
};
其中位域列表的形式为:
类型说明符 位域名: 位域长度

例如:
struct bs{
int a:8;
int b:2;
int c:6;
}data;
说明 data 为 bs 变量,共占两个字节。其中位域 a 占 8 位,位域 b 占 2 位,位域 c 占 6 位。
struct packed_struct {
unsigned int f1:1;
unsigned int f2:1;
unsigned int f3:1;
unsigned int f4:1;
unsigned int type:4;
unsigned int my_int:9;
} pack;
在这里,packed_struct 包含了 6 个成员:四个 1 位的标识符 f1…f4、一个 4 位的 type 和一个 9 位的 my_int。

对于位域的定义尚有以下几点说明:

一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。

struct bs{
unsigned a:4;
unsigned :4; /* 空域 /
unsigned b:4; /
从下一单元开始存放 */
unsigned c:4
}
在这个位域定义中,a 占第一字节的 4 位,后 4 位填 0 表示不使用,b 从第二字节开始,占用 4 位,c 占用 4 位。

由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。如果最大长度大于计算机的整数字长,一些编译器可能会允许域的内存重叠,另外一些编译器可能会把大于一个域的部分存储在下一个字中。

**位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的。**例如:

struct k{
int a:1;
int :2; /* 该 2 位不能使用 */
int b:3;
int c:2;
};
从以上分析可以看出,位域在本质上就是一种结构类型,不过其成员是按二进位分配的。

位域的使用
位域的使用和结构成员的使用相同,其一般形式为:
位域变量名.位域名
位域变量名->位域名
位域允许用各种格式输出。

main(){
struct bs{
unsigned a:1;
unsigned b:3;
unsigned c:4;
} bit,pbit;
bit.a=1; /
给位域赋值(应注意赋值不能超过该位域的允许范围) /
bit.b=7; /
给位域赋值(应注意赋值不能超过该位域的允许范围) /
bit.c=15; /
给位域赋值(应注意赋值不能超过该位域的允许范围) /
printf(“%d,%d,%d\n”,bit.a,bit.b,bit.c); /
以整型量格式输出三个域的内容 /
pbit=&bit; /
把位域变量 bit 的地址送给指针变量 pbit /
pbit->a=0; /
用指针方式给位域 a 重新赋值,赋为 0 /
pbit->b&=3; /
使用了复合的位运算符 “&=”,相当于:pbit->b=pbit->b&3,位域 b 中原有值为 7,与 3 作按位与运算的结果为 3(111&011=011,十进制值为 3) /
pbit->c|=1; /
使用了复合位运算符"|=",相当于:pbit->c=pbit->c|1,其结果为 15 /
printf(“%d,%d,%d\n”,pbit->a,pbit->b,pbit->c); /
用指针方式输出了这三个域的值 */
}
上例程序中定义了位域结构 bs,三个位域为 a、b、c。说明了 bs 类型的变量 bit 和指向 bs 类型的指针变量 pbit。这表示位域也是可以使用指针的。

typedef 关键字
我们使用typedef关键字为数据类型创建别名。它通常与结构一起使用,以简化声明变量的语法。

struct Distance{
int feet;
float inch;
};

int main() {
struct Distance d1, d2;
}
等同于

typedef struct Distance{
int feet;
float inch;
} distances;

int main() {
distances d1, d2;
}

struct complex
{
int imag;
float real;
};

struct number
{
struct complex comp;
int integers;
} num1, num2;
假设,你要设置num2的变量imag值为11,
则:
num2.comp.imag = 11;

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

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

相关文章

VSCode提交代码

VSCode提交代码方式&#xff1a; 先在电脑本地文件夹中打开git的bash窗口使用git clone https://github.com/xxxx/克隆仓库地址到本地&#xff0c;并生成一个项目的文件夹打开VSCode&#xff0c;点击文件按钮&#xff0c;打开加载项目的文件夹对于VSCode设置Git路径&#xff…

Three 材质纹理 (总结三)

THREE.MeshLambertMaterial&#xff08;网格 Lambert 材质&#xff09; 该材质使用基于非物理的Lambertian模型来计算反射率。可以用来创建暗淡的并不光亮的表面&#xff0c;该材质非常易用&#xff0c;而且会与场景中的光源产生反应。 MeshLambertMaterial属性 # .color : …

蓝桥杯刷题|02入门真题

[蓝桥杯 2022 省 B] 刷题统计 题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a 道题目&#xff0c;周六和周日每天做 b 道题目。请你帮小明计算&#xff0c;按照计划他将在第几天实现做题数大于等于 n 题? 输入格式 输入一行包含三个整数…

Linux之线程互斥

目录 一、问题引入 二、线程互斥 1、相关概念 2、加锁保护 1、静态分配 2、动态分配 3、锁的原理 4、死锁 三、可重入与线程安全 1、概念 2、常见的线程不安全的情况 3、常见的线程安全的情况 4、常见不可重入的情况 5、常见可重入的情况 6、可重入与线程安全联系…

google scholar谷歌学术搜索技巧合集【补充ing】

今天发现和百度学术更新速度差太多&#xff0c;引用数量也不对&#xff0c;故搜集谷歌学术搜索技巧&#xff0c;以尽快查找所需。 筛选合集&#xff1a; 谷歌学术高级搜索技巧大放送 - 知乎 Google Scholar 谷歌学术文献检索技巧总结 - 知乎 Google Scholar谷歌学术文献检索技…

Linux 部署 Samba 服务

一、Ubuntu 部署 Samba 1、安装 Samba # 更新本地软件包列表 sudo apt update# 安装Samba sudo apt install samba# 查看版本 smbd --version2、创建共享文件夹&#xff0c;并配置 Samba 创建需要共享的文件夹&#xff0c;并赋予权限&#xff1a; sudo mkdir /home/test sud…

vue3 依赖注入provide/inject

建议在非父子&#xff08;或不相关&#xff09;组件传值时进行使用 场景&#xff1a;App.vue 引用了A组件&#xff0c;A组件中有引用了B组件&#xff0c;甚至B有引用了C组件等时&#xff0c;这些组件共同使用了一个值&#xff0c;建议使用provide/inject的方式进行传值。 注意…

Kubernetes operator系列:webhook 知识学习【更新中】

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Kubernetes operator学习 系列文章&#xff0c;本节会对 kubernetes webhook 知识进行学习 本文的所有代码&#xff0c;都存储于github代码库&#xff1a;https://github.com/graham924/share-code-operator-st…

C语言例3-12:自增和自减运算的例子

i 先引用后加1--i 先减1后引用 代码如下&#xff1a; #include<stdio.h> int main(void) {int i2, j2;char c1d, c2D; //d(100) D(68)printf("i %d\n",i); //3, i3printf("j-- %d\n",j--); …

C++for语句

1.求平均年龄 班上有学生若干名,给出每名学生的年龄(整数),求班上所有学生的平均年龄,保留到小数点后两位 输入 第1行有一个整数n(1 <= n <=100),表示学生的人数;其后n行每行有1个整数,表示每个学生的年龄,取值为15~25 输出 一行,包含一个浮点数,为所求的平…

java实现压缩文件夹(层级压缩)下载,java打包压缩文件夹下载

工具类如下 打包下载方法&#xff1a;exportZip&#xff08;支持整个文件夹或单文件一起&#xff09; 注意:前端发送请求不能用ajax&#xff0c;form表单提交可以&#xff0c;location.href也可以&#xff0c;window.open也可以&#xff0c;总之就ajax请求就是不行 import com.…

生成式人工智能如何赋能SOC分析师?

以下是已经在全球SOC崭露头角的六大生成式人工智能应用。 在当今网络安全威胁日益严峻的形势下&#xff0c;安全运营中心(SOC)肩负着重大责任。然而&#xff0c;SOC分析师往往人手不足&#xff0c;工作繁重。生成式人工智能(GenAI)的出现为缓解这一困境带来了希望&#xff0c;使…

python:NP28---密码游戏

文章目录 前言一、题意描述输入描述&#xff1a;输出描述&#xff1a; 二、代码1.代码的实现2.读入数据 总结 前言 在python基础知识的学习中&#xff0c;我们很多时候会遇见让我们把数字拆分成各个位数的题&#xff0c;下面这道就是经典的数字拆分的l例题 一、题意 描述 牛…

工具篇--从零开始学Git

一、git概述 1.1版本控制方式 集中式版本控制工具 集中式版本控制工具&#xff0c;版本库是集中存放在中央服务器的&#xff0c; team 里每个人 work 时从中央服务器下载代码&#xff0c;是必须联网才能工作&#xff0c; 局域网或互联网&#xff0c;个人修改之…

IAB视频广告标准《数字视频和有线电视广告格式指南》之 简介、目录及视频配套广告 - 我为什么要翻译介绍美国人工智能科技公司IAB系列(2)

写在前面 谈及到中国企业走入国际市场&#xff0c;拓展海外营销渠道的时候&#xff0c;如果单纯依靠一个小公司去国外做广告&#xff0c;拉渠道&#xff0c;找代理公司&#xff0c;从售前到售后&#xff0c;都是非常不现实的。我们可以回想一下40年前&#xff0c;30年前&#x…

【学习记录】调试千寻服务+DTU+导远RTK过程的记录

最近调试车载定位的时候&#xff0c;遇到了一些问题&#xff0c;千寻服务已经正确配置到RTK里面了&#xff0c;但是导远的定位设备一直显示RTK浮动解&#xff0c;通过千寻服务后台查看状态&#xff0c;长时间显示不合法的GGA值。 首先&#xff0c;通过四处查资料&#xff0c;千…

嵌入式面经-ARM体系架构-计算机基础

嵌入式系统分层 操作系统的作用&#xff1a;向下管理硬件&#xff0c;向上提供接口&#xff08;API&#xff09; 应用开发&#xff1a;使用操作系统提供的接口&#xff08;API&#xff09;&#xff0c;做上层的应用程序开发&#xff0c;基本不用去关内核操作硬件是怎么实现的 …

网络架构层_服务器上下行宽带

网络架构层_服务器上下行宽带 解释一 云服务器ECS网络带宽的概念、计费、安全及使用限制_云服务器 ECS(ECS)-阿里云帮助中心 网络带宽是指在单位时间&#xff08;一般指的是1秒钟&#xff09;内能传输的数据量&#xff0c;带宽数值越大表示传输能力越强&#xff0c;即在单位…

蓝桥杯第十一届电子类单片机组程序设计

目录 前言 单片机资源数据包_2023&#xff08;点击下载&#xff09; 一、第十一届比赛原题 1.比赛题目 2.赛题解读 1&#xff09;计数功能 2&#xff09;连续按下无效按键 二、部分功能实现 1.计数功能的实现 2.连续按下无效按键的处理 3.其他处理 1&#xff09;对于…

verilog中,何时用reg和wire

何时用&#xff1f; 组合逻辑用wire&#xff0c;时序逻辑用reg。 reg 可以存储数据&#xff0c;wire则就是一根线&#xff0c;只能传递数据。 比如&#xff1f; 时序逻辑 always ( posedge clk or negedge rst_n) begin// big river goes to the east endinitial begin//…