- C 编程教程
- C - 首页
- C语言基础
- C - 概述
- C - 特性
- C - 历史
- C - 环境搭建
- C - 程序结构
- C - Hello World
- C - 编译过程
- C - 注释
- C - 词法单元
- C - 关键字
- C - 标识符
- C - 用户输入
- C - 基本语法
- C - 数据类型
- C - 变量
- C - 整数提升
- C - 类型转换
- C - 类型强制转换
- C - 布尔值
- C语言中的常量和字面量
- C - 常量
- C - 字面量
- C - 转义序列
- C - 格式说明符
- C语言中的运算符
- C - 运算符
- C - 算术运算符
- C - 关系运算符
- C - 逻辑运算符
- C - 位运算符
- C - 赋值运算符
- C - 一元运算符
- C - 自增和自减运算符
- C - 三元运算符
- C - sizeof 运算符
- C - 运算符优先级
- C - 其他运算符
- C语言中的决策
- C - 决策
- C - if 语句
- C - if...else 语句
- C - 嵌套 if 语句
- C - switch 语句
- C - 嵌套 switch 语句
- C语言中的循环
- C - 循环
- C - while 循环
- C - for 循环
- C - do...while 循环
- C - 嵌套循环
- C - 无限循环
- C - break 语句
- C - continue 语句
- C - goto 语句
- C语言中的函数
- C - 函数
- C - 主函数
- C - 按值传递函数调用
- C - 按引用传递函数调用
- C - 嵌套函数
- C - 可变参数函数
- C - 用户定义函数
- C - 回调函数
- C - 返回语句
- C - 递归
- C语言中的作用域规则
- C - 作用域规则
- C - 静态变量
- C - 全局变量
- C语言中的数组
- C - 数组
- C - 数组的特性
- C - 多维数组
- C - 将数组传递给函数
- C - 从函数返回数组
- C - 可变长数组
- C语言中的指针
- C - 指针
- C - 指针和数组
- C - 指针的应用
- C - 指针运算
- C - 指针数组
- C - 指针指向指针
- C - 将指针传递给函数
- C - 从函数返回指针
- C - 函数指针
- C - 指向数组的指针
- C - 指向结构体的指针
- C - 指针链
- C - 指针与数组
- C - 字符指针和函数
- C - 空指针
- C - 空指针
- C - 野指针
- C - 解引用指针
- C - 近指针、远指针和巨指针
- C - 指针数组的初始化
- C - 指针与多维数组
- C语言中的字符串
- C - 字符串
- C - 字符串数组
- C - 特殊字符
- C语言中的结构体和联合体
- C - 结构体
- C - 结构体和函数
- C - 结构体数组
- C - 自引用结构体
- C - 查找表
- C - 点 (.) 运算符
- C - 枚举 (或 enum)
- C - 结构体填充和打包
- C - 嵌套结构体
- C - 匿名结构体和联合体
- C - 联合体
- C - 位域
- C - Typedef
- C语言中的文件处理
- C - 输入 & 输出
- C - 文件 I/O (文件处理)
- C 预处理器
- C - 预处理器
- C - 指令
- C - 预处理器运算符
- C - 宏
- C - 头文件
- C语言中的内存管理
- C - 内存管理
- C - 内存地址
- C - 存储类
- 其他主题
- C - 错误处理
- C - 可变参数
- C - 命令执行
- C - 数学函数
- C - static 关键字
- C - 随机数生成
- C - 命令行参数
- C编程资源
- C - 问答
- C - 快速指南
- C - 速查表
- C - 有用资源
- C - 讨论
C语言中的结构体
C语言中的结构体
C 语言中的结构体是一种派生数据类型或用户自定义数据类型。我们使用关键字struct来定义一个自定义的数据类型,该类型将不同类型的元素组合在一起。数组和结构体之间的区别在于,数组是相同类型元素的同构集合,而结构体可以包含不同类型的元素,这些元素存储在一起并由名称标识。
我们经常需要处理具有某种关系的不同数据类型的值。例如,一本书由其标题(字符串)、作者(字符串)、价格(双精度浮点数)、页数(整数)等描述。与其使用四个不同的变量,不如将这些值存储在一个struct变量中。
声明(创建)结构体
您可以使用"struct"关键字后跟结构体标签(结构体名称)来创建(声明)结构体,并在花括号内声明结构体的所有成员及其数据类型。
要定义结构体,必须使用struct语句。struct 语句定义了一种新的数据类型,该类型具有多个成员。
结构体声明语法
声明结构体的格式(语法)如下所示:
struct [structure tag]{ member definition; member definition; ... member definition; } [one or more structure variables];
结构体标签是可选的,每个成员定义都是一个正常的变量定义,例如"int i;"或"float f;"或任何其他有效的变量定义。
在结构体定义的末尾,在最后一个分号之前,可以指定一个或多个结构体变量,但这是可选的。
示例
在下面的示例中,我们正在为 Book 声明一个结构体,以存储书籍的详细信息:
struct book{ char title[50]; char author[50]; double price; int pages; } book1;
这里,我们在结构体定义的末尾声明了结构体变量book1。但是,您也可以在不同的语句中单独进行此操作。
结构体变量声明
要访问和操作结构体的成员,首先需要声明其变量。要声明结构体变量,请编写结构体名称以及"struct"关键字,后跟结构体变量的名称。此结构体变量将用于访问和操作结构体成员。
示例
以下语句演示了如何声明(创建)结构体变量
struct book book1;
通常,结构体在程序中第一个函数定义之前、在include语句之后声明。这样,派生类型就可以用于在任何函数内部声明其变量。
结构体初始化
初始化struct 变量是通过将每个元素的值放在花括号内来完成的。
示例
以下语句演示了结构体的初始化
struct book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325};
访问结构体成员
要访问结构体的成员,首先需要声明一个结构体变量,然后使用点 (.) 运算符以及结构体变量。
示例 1
struct 变量 book1 的四个元素都是使用点 (.) 运算符访问的。因此,"book1.title" 指的是标题元素,"book1.author" 是作者姓名,"book1.price" 是价格,"book1.pages" 是第四个元素(页数)。
请看下面的例子:
#include <stdio.h> struct book{ char title[10]; char author[20]; double price; int pages; }; int main(){ struct book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325}; printf("Title: %s \n", book1.title); printf("Author: %s \n", book1.author); printf("Price: %lf\n", book1.price); printf("Pages: %d \n", book1.pages); printf("Size of book struct: %d", sizeof(struct book)); return 0; }
输出
运行代码并检查其输出:
Title: Learn C Author: Dennis Ritchie Price: 675.500000 Pages: 325 Size of book struct: 48
示例 2
在上面的程序中,我们将进行一个小修改。在这里,我们将类型定义和变量声明放在一起,如下所示:
struct book{ char title[10]; char author[20]; double price; int pages; } book1;
请注意,如果以这种方式声明 struct 变量,则不能使用花括号对其进行初始化。相反,需要分别为每个元素赋值。
#include <stdio.h> #include <string.h> struct book{ char title[10]; char author[20]; double price; int pages; } book1; int main(){ strcpy(book1.title, "Learn C"); strcpy(book1.author, "Dennis Ritchie"); book1.price = 675.50; book1.pages = 325; printf("Title: %s \n", book1.title); printf("Author: %s \n", book1.author); printf("Price: %lf \n", book1.price); printf("Pages: %d \n", book1.pages); return 0; }
输出
执行此代码时,将产生以下输出:
Title: Learn C Author: Dennis Ritchie Price: 675.500000 Pages: 325
复制结构体
可以使用赋值 (=) 运算符直接复制结构体。您还可以使用赋值运算符 (=) 将一个结构体的成员值赋给另一个结构体的成员。
让我们有两个 struct book 变量,book1 和book2。变量book1在声明时进行了初始化,我们希望将其元素的相同值赋给book2。
我们可以分别为各个元素赋值,如下所示:
struct book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325}, book2; strcpy(book2.title, book1.title); strcpy(book2.author, book1.author); book2.price = book1.price; book2.pages = book1.pages;
请注意,使用strcpy() 函数为字符串变量赋值,而不是使用"= 运算符"。
示例
您还可以将 book1 赋给 book2,以便 book1 的所有元素分别赋给 book2 的元素。请看下面的程序代码:
#include <stdio.h> #include <string.h> struct book{ char title[10]; char author[20]; double price; int pages; }; int main(){ struct book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325}, book2; book2 = book1; printf("Title: %s \n", book2.title); printf("Author: %s \n", book2.author); printf("Price: %lf \n", book1.price); printf("Pages: %d \n", book1.pages); printf("Size of book struct: %d", sizeof(struct book)); return 0; }
输出
运行代码并检查其输出:
Title: Learn C Author: Dennis Ritchie Price: 675.500000 Pages: 325 Size of book struct: 48
结构体作为函数参数
您可以像传递任何其他变量或指针一样,将结构体作为函数参数传递。
示例
请看下面的程序代码。它演示了如何将结构体作为函数参数传递:
#include <stdio.h> #include <string.h> struct Books{ char title[50]; char author[50]; char subject[100]; int book_id; }; /* function declaration */ void printBook(struct Books book); int main(){ struct Books Book1; /* Declare Book1 of type Book */ struct Books Book2; /* Declare Book2 of type Book */ /* book 1 specification */ strcpy(Book1.title, "C Programming"); strcpy(Book1.author, "Nuha Ali"); strcpy(Book1.subject, "C Programming Tutorial"); Book1.book_id = 6495407; /* book 2 specification */ strcpy(Book2.title, "Telecom Billing"); strcpy(Book2.author, "Zara Ali"); strcpy(Book2.subject, "Telecom Billing Tutorial"); Book2.book_id = 6495700; /* print Book1 info */ printBook(Book1); /* Print Book2 info */ printBook(Book2); return 0; } void printBook(struct Books book){ printf("Book title : %s\n", book.title); printf("Book author : %s\n", book.author); printf("Book subject : %s\n", book.subject); printf("Book book_id : %d\n", book.book_id); }
输出
编译并执行上述代码时,将产生以下结果:
Book title : C Programming Book author : Nuha Ali Book subject : C Programming Tutorial Book book_id : 6495407 Book title : Telecom Billing Book author : Zara Ali Book subject : Telecom Billing Tutorial Book book_id : 6495700
指向结构体的指针
您可以像定义指向任何其他变量的指针一样定义指向结构体的指针。
指向结构体的指针声明
您可以如下声明指向结构体的指针(或结构体指针):
struct Books *struct_pointer;
指向结构体的指针初始化
您可以在上述指针变量struct_pointer中存储结构体变量的地址。要查找结构体变量的地址,请在结构体名称前放置'&'运算符,如下所示:
struct_pointer = & book1;
让我们将 struct 变量的地址存储在 struct 指针变量中。
struct book{ char title[10]; char author[20]; double price; int pages; }; struct book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325}, struct book *strptr;
使用指向结构体的指针访问成员
要使用指向该结构体的指针访问结构体的成员,必须使用→ 运算符,如下所示:
struct_pointer->title;
C 定义→符号与 struct 指针一起用作间接运算符(也称为结构体解引用运算符)。它有助于访问 struct 变量的元素,该指针引用到该元素。
示例
在这个例子中,strptr 是指向 struct book book1 变量的指针。因此,strrptr→title 返回标题,就像 book1.title 一样。
#include <stdio.h> #include <string.h> struct book{ char title[10]; char author[20]; double price; int pages; }; int main (){ struct book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325}; struct book *strptr; strptr = &book1; printf("Title: %s \n", strptr -> title); printf("Author: %s \n", strptr -> author); printf("Price: %lf \n", strptr -> price); printf("Pages: %d \n", strptr -> pages); return 0; }
输出
运行此代码时,将产生以下输出:
Title: Learn C Author: Dennis Ritchie Price: 675.500000 Pages: 325
注意: 点 (.) 运算符用于通过 struct 变量访问结构体元素。要通过其指针访问元素,必须使用 间接访问 (->) 运算符。
.结构体变量类似于基本类型的普通变量,因为它可以拥有结构体数组,可以将结构体变量传递给函数,以及从函数返回结构体。
您可能已经注意到,在声明变量或指针时需要在前面加上“struct 类型”。这可以通过使用 typedef 关键字创建简写符号来避免,我们将在后续章节中解释。
结构体用于不同的应用程序,例如数据库、文件管理应用程序以及处理复杂的数据结构,如树和链表。
位域
位域 允许在结构体中打包数据。当内存或数据存储空间有限时,这尤其有用。典型示例包括:
- 将多个对象打包到一个机器字中,例如,可以压缩 1 位标志。
- 读取外部文件格式 - 例如,可以读取非标准文件格式,例如 9 位整数。
声明
C 允许我们在结构体定义中通过在变量后面加上 :bit 长度来实现这一点。例如:
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..f3,一个 4 位类型和一个 9 位 my_int。
C 会自动尽可能紧凑地打包上述位域,前提是字段的最大长度小于或等于计算机的整数字长。如果不是这种情况,则某些编译器可能会允许字段的内存重叠,而其他编译器则会将下一个字段存储在下一个字中。