C 语言结构体(struct)

C 语言结构体(struct)

在本教程中,您将学习C语言编程中的结构类型。您将借助示例学习定义和使用结构。

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

C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。

结构用于表示一条记录,假设您想要跟踪图书馆中书本的动态,您可能需要跟踪每本书的下列属性:

  • Title
  • Author
  • Subject
  • Book ID

定义结构

为了定义结构,您必须使用 struct 关键词。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:

struct tag { member-listmember-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;

在一般情况下,tag、member-list、variable-list 这 3 部分至少要出现 2 个。以下为示例:

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//同时又声明了结构体变量s1
//这个结构体并没有标明其标签
struct 
{int a;char b;double c;
} s1;//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//结构体的标签被命名为SIMPLE,没有声明变量
struct SIMPLE
{int a;char b;double c;
};
//用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;

在上面的声明中,第一个和第二声明被编译器当作两个完全不同的类型,即使他们的成员列表是一样的,如果令 t3=&s1,则是非法的。

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

//此结构体的声明包含了其他的结构体
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;
}

嵌套结构

您可以在C语言编程中的结构内创建结构。例如,

struct complex
{int imag;float real;
};struct number
{struct complex comp;int integers;
} num1, num2;

假设,你要设置num2的变量imag值为11,怎么做呢?看下面示例:

num2.comp.imag = 11;

为什么在C中使用结构?

假设您要存储有关一个人的信息:他/她的姓名,身份证号和薪水。您可以创建不同的变量name,citNo和salary存储此信息。

如果您需要存储多个人的信息怎么办?现在,你需要为每个人每个信息创建不同的变量:name1,citNo1,salary1,name2,citNo2,salary2, 等。

更好的方法是在单个名称Person结构下收集所有相关信息,并将其用于每个人。

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

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

相关文章

Java 的异常体系

Java 中 Throwable 是所有异常和错误的超类&#xff0c;两个直接子类是 Error&#xff08;错误&#xff09;和 Exception&#xff08;异常&#xff09; 在Java中&#xff0c;异常的根类是java.lang.Throwable类&#xff0c;而根类又分为两大类&#xff1a;Error和Exception&…

浅谈开源和闭源的认知

目录 在大型模型的发展中&#xff0c;开源和闭源两种截然不同的开发模式扮演着关键的角色。开源模式通过促进技术共享&#xff0c;吸引了大量优秀人才的加入&#xff0c;从而推动了大模型领域的不断创新。与此相反&#xff0c;闭源模式则着重于保护商业利益和技术优势&#xff…

【uni-app】设置背景颜色相关

1. 全局页面背景色设置&#xff1a; 在App.vue的style样式表中设置 <style> page {background-color: #F0AD4E; } </style> 2. 顶部导航栏背景色设置&#xff1a; 在pages.json页面路由中&#xff0c;globalStyle设置 "globalStyle": {"navi…

物流实时数仓:采集通道搭建

系列文章目录 物流实时数仓&#xff1a;环境搭建 文章目录 系列文章目录前言一、环境准备1.前置环境2.hbase安装1.上传并解压2.配置环境变量3.拷贝jar包4.编写配置文件5.分发配置文件 3.Redis安装1.安装需要的编译环境2.上传并解压文件3.编译安装4.后台访问 4.ClickHouse安装5…

OpenCvSharp从入门到实践-(01)认识OpenCvSharp开发环境搭建

目录 一、OpenCV 二、OpenCvSharp 三、OpenCvSharp开发环境搭建 四、下载 五、其他 一、OpenCV OpenCV是基于Apache2.0许可&#xff08;开源&#xff09;发行的跨平台计算机视觉和机器学习函数库&#xff0c;支持Windows、Linux、Android和Mac OS操作系统。OpenCV由一系…

Oracle for Windows安装和配置——Oracle for Windows net配置

2.3. Oracle for Windows net配置 2.3.1. Oracle net配置 2.3.1.1. Oracle net简介 前述章节中,我们只是安装了数据库软件,创建了数据库,测试在服务器本地连接查询数据库。但还不能通过网络远程连接访问数据库,因为我们还没配置用来远程连接访问该数据库的组件Oracle ne…

【Linux】缓冲区+磁盘+动静态库

一、缓冲区 1、缓冲区的概念 缓冲区的本质就是一段用作缓存的内存。 2、缓冲区的意义 节省进程进行数据IO的时间。进程使用fwrite等函数把数据拷贝到缓冲区或者外设中。 3、缓冲区刷新策略 3.1、立即刷新&#xff08;无缓冲&#xff09;——ffush() 情况很少&#xff0c…

【蓝桥杯 第十五届模拟赛 Java B组】训练题(A - I)

目录 A、求全是字母的最小十六进制数 B、Excel表格组合 C、求满足条件的日期 D、 取数字 - 二分 &#xff08;1&#xff09;暴力 &#xff08;2&#xff09;二分 E、最大连通块 - bfs F、哪一天&#xff1f; G、信号覆盖 - bfs &#xff08;1&#xff09;bfs&#xf…

【前端学java】java中的日期操作(12)

往期回顾&#xff1a; 【前端学java】JAVA开发的依赖安装与环境配置 &#xff08;0&#xff09;【前端学 java】java的基础语法&#xff08;1&#xff09;【前端学java】JAVA中的packge与import&#xff08;2&#xff09;【前端学java】面向对象编程基础-类的使用 &#xff08…

力扣labuladong——一刷day42

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣222. 完全二叉树的节点个数 前言 计算二叉树的节点个数&#xff0c;计算满二叉树的节点个数&#xff0c;计算完全二叉树的节点个数 一、力扣222. 完全…

使用Python的turtle模块绘制玫瑰花图案(含详细Python代码与注释)

1.1引言 turtle模块是Python的标准库之一&#xff0c;它提供了一个绘图板&#xff0c;让我们可以在屏幕上绘制各种图形。通过使用turtle&#xff0c;我们可以创建花朵、叶子、复杂的图案等等。本博客将介绍如何使用turtle模块实现绘制图形的过程&#xff0c;并展示最终结果。 …

创建一个用户test且使用testtab表空间及testtemp临时表空间并授予其权限,密码随意

文章目录 1、连接到数据库2、创建表空间3、创建用户4、授予权限5、测试 1、连接到数据库 sqlplus / as sysdba2、创建表空间 创建testtab表空间 CREATE TABLESPACE testtab DATAFILE /u01/app/oracle/oradata/orcl/testtab.dbf SIZE 50M AUTOEXTEND ON NEXT 5M MAXSIZE …

Unity中Shader法线贴图(下)理论篇

文章目录 前言一、采样出错的原因二、切线空间是什么&#xff1f;切线空间图解&#xff1a; 三、计算方式1、统一变换到切线空间下进行计算2、统一变换到世界空间下进行计算 四、一般统一变换到世界空间下的坐标进行计算1、求M^-1^2、求出n~w~ 前言 这篇文章&#xff0c;主要解…

[Android] Amazon 的 android 音视频开发文档

https://developer.amazon.com/zh/docs/fire-tv/audio-video-synchronization.html#22-getplaybackheadposition-api-level-3https://developer.amazon.com/zh/docs/fire-tv/audio-video-synchronization.html#22-getplaybackheadposition-api-level-3

车载毫米波雷达行业发展1——概述

1.1 毫米波雷达定义及产品演进 1.1.1 毫米波雷达定义 毫米波雷达(mmWave Radar)是指工作在毫米波波段的雷达&#xff0c;其频域介于 30&#xff5e;300GHz&#xff0c;波长1~10mm。毫米波雷达稳定性高&#xff0c;抗干扰能力强&#xff0c;可穿透雾、烟、灰尘环境&#xff0…

Java基础-----StringBuffer和StringBuilder

文章目录 1.StringBuffer1.1 构造方法1.2 常用方法 2.StringBuilder3.String、StringBuffer、StringBuilder的区别 1.StringBuffer 内容可变的字符串类&#xff0c;适应StringBuffer来对字符串的内容进行动态操作&#xff0c;不会产生额外的对象。StringBuffer在初始时&#x…

AI集成ChatGPT敲代码神器Copilot

&#x1f4d1;前言 本文主要是AI工具Copilot解读文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日一句&#xff1a;努力…

实现领域驱动设计-应用结构

写在前面&#xff1a; DDD的一大好处便是它并不需要使用特定的架构。我们可以在整个系统中使用多种风格的架构。有些架构包围着领域模型&#xff0c;能够全局性地影响系统&#xff0c;而有些架构则满足了某些特定的需求。我们的目标是选择适合于自己的架构和架构模式。 在选择架…

【HarmonyOS开发】配置开发工具DevEco Studio

1、下载 注意&#xff1a; 1、安装过程中&#xff0c;一定要自定义安装位置&#xff0c;包比较大&#xff0c;包比较大&#xff0c;包比较大&#xff01;&#xff01;&#xff01; 2、可以将该工具添加到右键中&#xff0c;否则&#xff0c;如果你的项目不是HarmonyOS&#xff…

分布式系统中的乐观和错误假设

避免协调是让我们构建的分布式系统超越单机性能的一个基本要素。当我们构建避免协调的系统时&#xff0c;我们最终构建的组件会假设其他组件在做什么。这一点也很重要。如果两个组件不能在每一步操作后都互相检查&#xff0c;那么它们就需要对其他组件正在进行的行为做出假设。…