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 - Main 函数 C - 按值调用函数 C - 按引用调用函数 C - 嵌套函数 C - 可变参数函数 C - 用户定义函数 C - 回调函数 C - return 语句 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 - 指针 vs 数组 C - 字符指针和函数 C - NULL 指针 C - void 指针 C - 悬垂指针 C - 解引用指针 C - Near、Far 和 Huge 指针 C - 指针数组的初始化 C - 指针与多维数组

C 语言中的字符串

C - 字符串 C - 字符串数组 C - 特殊字符

C 语言的结构体和联合

C - 结构体 C - 结构体和函数 C - 结构体数组 C - 自引用结构 C - 查找表 C - 点 (.) 运算符 C - 枚举(或 enum) C - 结构填充和打包 C - 嵌套结构 C - 匿名结构和联合 C - 联合 C - Bit 位字段 C - Typedef

C 语言中的文件处理

C - 输入和输出 C - 文件 I/O(文件处理)

C 语言中的预处理器

C - 预处理器 C - #pragma 编译指示 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 来定义一种自定义数据类型,将不同类型的元素组合在一起。数组和结构体的区别在于,数组是相似类型的同质集合,而结构体可以相邻存储不同类型的元素,并通过名称进行标识。

我们经常需要处理不同数据类型的值,这些值之间存在一定的关系。例如,一本 book 由其 title(字符串)、author(字符串)、price(双精度型)、number of pages(整数型)等描述。这些值可以存储在一个 struct 变量中,而无需使用四个不同的变量。

声明(创建)结构体

您可以使用 "struct" 关键字加上structure_tag(结构体名称)来创建(声明)结构体,并在花括号内声明结构体的所有成员及其数据类型。

要定义结构体,必须使用 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 book book1 = {"Learn C", "Dennis Ritchie", 675.50, 325};

访问结构体成员

要访问结构体成员,首先需要声明一个结构体变量,然后使用点 (.) 运算符以及该结构体变量。

示例 1

使用点 (.) 运算符访问结构体变量 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 
", book1.title);
   printf("Author: %s 
", book1.author);
   printf("Price:  %lf
", book1.price);
   printf("Pages:  %d 
", 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;

请注意,如果您以这种方式声明结构体变量,则不能使用花括号初始化它。相反,需要对元素单独赋值。

#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 
", book1.title);
   printf("Author: %s 
", book1.author);
   printf("Price: %lf 
", book1.price);
   printf("Pages: %d 
", book1.pages);
   return 0;
}

输出

当您执行此代码时,它将产生以下输出 -

Title: Learn C 
Author: Dennis Ritchie 
Price: 675.500000 
Pages: 325

复制结构体

赋值运算符 (=) 可用于直接复制结构体。您也可以使用赋值运算符 (=) 将一个结构体成员的值赋给另一个结构体。

假设有两个结构体 book 变量,book1book2。变量 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() 函数 将值赋给 string 变量,而不是使用"="运算符。

示例

您还可以将 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 
", book2.title);
   printf("Author: %s 
", book2.author);
   printf("Price: %lf 
", book1.price);
   printf("Pages: %d 
", 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;
};

/* 函数声明 */
void printBook(struct Books book);

int main(){
    struct Books Book1; /* 将 Book1 声明为 Book 类型 */
    struct Books Book2; /* 将 Book2 声明为 Book 类型 */
    
    /* 书 1 的说明 */
   strcpy(Book1.title, "C Programming");
   strcpy(Book1.author, "Nuha Ali"); 
   strcpy(Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;
    
    /* 书 2 的说明 */
   strcpy(Book2.title, "Telecom Billing");
   strcpy(Book2.author, "Zara Ali");
   strcpy(Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
    
    /* 打印 Book1 的信息 */
    printBook(Book1);
    
    /* 打印 Book2 的信息 */
    printBook(Book2);
    return 0;
}

void printBook(struct Books book){

   printf("Book title : %s
", book.title);
   printf("Book author : %s
", book.author);
   printf("Book subject : %s
", book.subject);
   printf("Book book_id : %d
", 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 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 语言将 符号定义为与结构体指针一起使用的 间接运算符(也称为 结构体解引用运算符)。它有助于访问指针引用的结构体变量的元素。

示例

在此示例中,strptr 是指向 struct book book1 变量的指针。因此,strrptrtitle 返回标题,就像 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 
", strptr -> title);
   printf("Author: %s 
", strptr -> author);
   printf("Price: %lf 
", strptr -> price);
   printf("Pages: %d 
", strptr -> pages); 
   return 0;
}

输出

运行此代码时,将产生以下输出 -

Title: Learn C 
Author: Dennis Ritchie 
Price: 675.500000 
Pages: 325

注意:点运算符 (.) 用于通过 struct 变量访问结构体元素。要通过其指针访问元素,必须使用 间接寻址 (->) 运算符

结构体变量类似于普通的主类型变量,您可以拥有一个结构体数组,可以将结构体变量传递给函数,也可以从函数返回一个结构体。

您可能已经注意到,在声明变量或指针时,需要在名称前加上"结构体类型"前缀。可以通过使用 typedef 关键字创建简写符号来避免这种情况,我们将在后续章节中对此进行解释。

结构体用于不同的应用程序,例如数据库、文件管理应用程序,以及处理复杂的数据结构,例如树形结构和链表。

位域

位域 允许将数据打包到结构体中。当内存或数据存储紧张时,这尤其有用。典型示例包括:-

  • 将多个对象打包成一个机器字,例如,可以压缩 1 位标志。
  • 读取外部文件格式 - 可以读取非标准文件格式,例如 9 位整数。

声明

C 语言允许我们在结构体定义中通过在变量后添加 :bit length 来实现此目的。例如:-

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 语言会自动尽可能紧凑地打包上述位字段,前提是这些字段的最大长度小于或等于计算机的整数字长。如果不是这种情况,某些编译器可能会允许这些字段的内存重叠,而其他编译器则会将下一个字段存储在下一个字中。