ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
#### 17. 结构体 C 数组允许定义可存储相同类型数据项的变量,**结构**是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。 结构用于表示一条记录,假设您想要跟踪图书馆中书本的动态,您可能需要跟踪每本书的下列属性: * Title * Author * Subject * Book ID **定义结构** 为了定义结构,您必须使用 **struct** 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下: ~~~ struct name{ member-list; member-list; ... }name_tag, ~~~ *name* 是结构的标签。 *member-list* 是标准的变量定义,比如 int i;或者 float f,或者其它有效的变量定义。 *name_tag* 结构变量,定义在结构的末尾,最后一个分号之前,你可以指定一个或多个结构变量,下面是声明 Book 的结构方式: ~~~ struct Books{ char title[50]; char author[50]; char subject[100]; int book_id; } book; ~~~ 注意:在定义结构体的时候**name、member-list、name\_tag** 这 3 部分至少要出现 2 个。 **结构体变量的初始化** 和其它类型变量一样,在初始化的时候可以指定初始值。 ~~~ //定义一个 Books 结构,类似于 Java 中的数据 bean struct Books { char title[50]; char author[50]; char subject[100]; int book_id; double rmb; } book = {"Java", "Android", "C 语言", 666, 55.5}; void main(){ //打印 Books printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\nrmb: %f\n", book.title, book.author, book.subject, book.book_id, book.rmb); } ~~~ 输出: ~~~ title : Java author: Android subject: C 语言 book_id: 666 rmb: 55.500000 ~~~ **访问结构成员** ~~~ struct Books2 { char title[50]; char author[50]; char subject[100]; int book_id; }; void main(){ //访问 Books2 结构成员 struct Books2 Books2A;//声明 Books2A 类型为 Books2 struct Books2 Books2B;//声明 Books2B 类型为 Books2 //Books2A 详述 strcpy(Books2A.title, "C Plus"); strcpy(Books2A.author, "Nuha Ali"); strcpy(Books2A.subject, "C"); Books2A.book_id = 666888; //Books2B 详述 strcpy(Books2B.title, "C++ Plus"); strcpy(Books2B.author, "DevYK"); strcpy(Books2B.subject, "C++"); Books2B.book_id = 666999; // 输出 Book1 信息 printf("Book 1 title : %s\n", Books2A.title); printf("Book 1 author : %s\n", Books2A.author); printf("Book 1 subject : %s\n", Books2A.subject); printf("Book 1 book_id : %d\n", Books2A.book_id); // 输出 Book2 信息 printf("Book 2 title : %s\n", Books2B.title); printf("Book 2 author : %s\n", Books2B.author); printf("Book 2 subject : %s\n", Books2B.subject); printf("Book 2 book_id : %d\n", Books2B.book_id); } ~~~ 输出: ~~~ Book 1 title : C Plus Book 1 author : Nuha Ali Book 1 subject : C Book 1 book_id : 666888 Book 2 title : C++ Plus Book 2 author : DevYK Book 2 subject : C++ Book 2 book_id : 666999 ~~~ **结构作为函数参数** ~~~ //函数声明 void printBook(struct Books2 books2); void main(){ //访问 Books2 结构成员 struct Books2 Books2A;//声明 Books2A 类型为 Books2 struct Books2 Books2B;//声明 Books2B 类型为 Books2 //Books2A 详述 ,将 CPlus copy 到 title 中 strcpy(Books2A.title, "C Plus"); strcpy(Books2A.author, "Nuha Ali"); strcpy(Books2A.subject, "C"); Books2A.book_id = 666888; //Books2B 详述 strcpy(Books2B.title, "C++ Plus"); strcpy(Books2B.author, "DevYK"); strcpy(Books2B.subject, "C++"); Books2B.book_id = 666999; // 输出 Book1 信息 printf("Book 1 title : %s\n", Books2A.title); printf("Book 1 author : %s\n", Books2A.author); printf("Book 1 subject : %s\n", Books2A.subject); printf("Book 1 book_id : %d\n", Books2A.book_id); // 输出 Book2 信息 printf("Book 2 title : %s\n", Books2B.title); printf("Book 2 author : %s\n", Books2B.author); printf("Book 2 subject : %s\n", Books2B.subject); printf("Book 2 book_id : %d\n", Books2B.book_id); printf("\n\n\n"); //结构作为函数参数 printBook(Books2A); printBook(Books2B); } void printBook(struct Books2 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 1 title : C Plus Book 1 author : Nuha Ali Book 1 subject : C Book 1 book_id : 666888 Book 2 title : C++ Plus Book 2 author : DevYK Book 2 subject : C++ Book 2 book_id : 666999 Book title : C Plus Book author : Nuha Ali Book subject : C Book book_id : 666888 Book title : C++ Plus Book author : DevYK Book subject : C++ Book book_id : 666999 ~~~ **指向结构的指针** 您可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似,如下所示: ~~~ struct Books *struct_pointer; ~~~ 现在,您可以在上述定义的指针变量中存储结构变量的地址。为了查找结构变量的地址,请把 & 运算符放在结构名称的前面,如下所示: ~~~ struct_pointer = &Book1; ~~~ 为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符,如下所示: ~~~ struct_pointer->title; ~~~ 例子: ~~~ //定义指向结构的指针 void printBookZZ(struct Books2 *books2); void main(){ //访问 Books2 结构成员 struct Books2 Books2A;//声明 Books2A 类型为 Books2 struct Books2 Books2B;//声明 Books2B 类型为 Books2 //Books2A 详述 ,将 CPlus copy 到 title 中 strcpy(Books2A.title, "C Plus"); strcpy(Books2A.author, "Nuha Ali"); strcpy(Books2A.subject, "C"); Books2A.book_id = 666888; //Books2B 详述 strcpy(Books2B.title, "C++ Plus"); strcpy(Books2B.author, "DevYK"); strcpy(Books2B.subject, "C++"); Books2B.book_id = 666999; //通过内存地址传递信息,为了查找结构变量的地址,请把 & 运算符放在结构名称的前面 printBookZZ(&Books2A); printBookZZ(&Books2B); } /** * 为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符,如下所示: * @param book */ void printBookZZ(struct Books2 *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); } ~~~ **位域** 有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。 所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。 典型的实例: * 用 1 位二进位存放一个开关量时,只有 0 和 1 两种状态。 * 读取外部文件格式——可以读取非标准的文件格式。 `位域ed 定义:` ~~~ struct 位域结构名称{ 位域列表 }; ~~~ 位域列表的形式为: ~~~ 类型说明符 位域名:位域长度 ~~~ 例如: ~~~ struct bean { int a:8; int b:4; int c:4; }data; ~~~ 说明 data 为 bean 变量,共占 2个字节。其中位域 a 占 8 位,位域 b 占 4 位,位域 c 占 4 位。 注意: * 一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如: ~~~ struct bean{ unsigned a:4; unsigned :4;//空域 unsigned b:4;//从下一个单元开始存放 unsigned c:4; } ~~~ 在这个位域定义中共占用 2 个字节,a 占第一字节的 4 位,后 4 位填 0 表示不使用,b 从第二字节开始,占用 4 位,c 占用 4 位。 > * 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。如果最大长度大于计算机的整数字长,一些编译器可能会允许域的内存重叠,另外一些编译器可能会把大于一个域的部分存储在下一个字中。 > * 位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如: > > ~~~ > struct k{ > int a:1; > int :2; /* 该 2 位不能使用 */ > int b:3; > int c:2; > }; > ~~~ > > 从以上分析可以看出,位域在本质上就是一种结构类型,不过其成员是按二进位分配的。 **位域的使用** 位域的使用和结构成员的使用相同,其一般形式为: > 位域变量名.位域名 > > 位域变量名->位域名 位域允许用各种格式输出。 例子: ~~~ void main(){ //位域 struct bs { unsigned int a:1;//占 位段a 1 位 unsigned b:6;//占 位段b 3 位 unsigned c:7;//占 位段c 4 位 } bit, *pbit; // 给位域赋值(应注意赋值不能超过该位域的允许范围) bit.a = 1; //以二进制 1 表示 1 bit位 bit.b = 50;//以二进制 110010 表示 6 bit位 bit.c = 100;//以二进制 1100100 标志 7 bit位 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 中原有值为 50,与 3 作按位与运算的结果为 2(110010&011=010,十进制值为 2) pbit->c|=1; //使用了复合位运算符"|=",相当于:pbit->c=pbit->c|1,其结果为 (1100100 | 0000001)= 1100101 = 101 printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); //用指针方式输出了这三个域的值 } ~~~ 输出: ~~~ 1,50,100 0,2,101 ~~~