#### 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
~~~
- 前言
- JNI基础知识
- C语言知识点总结
- ①基本语法
- ②数据类型
- 枚举类型
- 自定义类型(类型定义)
- ③格式化输入输出
- printf函数
- scanf函数
- 编程规范
- ④变量和常量
- 局部变量和外部变量
- ⑤类型转换
- ⑥运算符
- ⑦结构语句
- 1、分支结构(选择语句)
- 2、循环结构
- 退出循环
- break语句
- continue语句
- goto语句
- ⑧函数
- 函数的定义和调用
- 参数
- 函数的返回值
- 递归函数
- 零起点学通C语言摘要
- 内部函数和外部函数
- 变量存储类别
- ⑨数组
- 指针
- 结构体
- 联合体(共用体)
- 预处理器
- 预处理器的工作原理
- 预处理指令
- 宏定义
- 简单的宏
- 带参数的宏
- 预定义宏
- 文件包含
- 条件编译
- 内存中的数据
- C语言读文件和写文件
- JNI知识点总结
- 前情回顾
- JNI规范
- jni开发
- jni开发中常见的错误
- JNI实战演练
- C++(CPP)在Android开发中的应用
- 掘金网友总结的音视频开发知识
- 音视频学习一、C 语言入门
- 1.程序结构
- 2. 基本语法
- 3. 数据类型
- 4. 变量
- 5. 常量
- 6. 存储类型关键字
- 7. 运算符
- 8. 判断
- 9. 循环
- 10. 函数
- 11. 作用域规则
- 12. 数组
- 13. 枚举
- 14. 指针
- 15. 函数指针与回调函数
- 16. 字符串
- 17. 结构体
- 18. 共用体
- 19. typedef
- 20. 输入 & 输出
- 21.文件读写
- 22. 预处理器
- 23.头文件
- 24. 强制类型转换
- 25. 错误处理
- 26. 递归
- 27. 可变参数
- 28. 内存管理
- 29. 命令行参数
- 总结
- 音视频学习二 、C++ 语言入门
- 1. 基本语法
- 2. C++ 关键字
- 3. 数据类型
- 4. 变量类型
- 5. 变量作用域
- 6. 常量
- 7. 修饰符类型
- 8. 存储类
- 9. 运算符
- 10. 循环
- 11. 判断
- 12. 函数
- 13. 数学运算
- 14. 数组
- 15. 字符串
- 16. 指针
- 17. 引用
- 18. 日期 & 时间
- 19. 输入输出
- 20. 数据结构
- 21. 类 & 对象
- 22. 继承
- 23. 重载运算符和重载函数
- 24. 多态
- 25. 数据封装
- 26. 接口(抽象类)
- 27. 文件和流
- 28. 异常处理
- 29. 动态内存
- 30. 命名空间
- 31. 预处理器
- 32. 多线程
- 总结
- 音视频学习 (三) JNI 从入门到掌握
- 音视频学习 (四) 交叉编译动态库、静态库的入门学习
- 音视频学习 (五) Shell 脚本入门
- 音视频学习 (六) 一键编译 32/64 位 FFmpeg 4.2.2
- 音视频学习 (七) 掌握音频基础知识并使用 AudioTrack、OpenSL ES 渲染 PCM 数据
- 音视频学习 (八) 掌握视频基础知识并使用 OpenGL ES 2.0 渲染 YUV 数据
- 音视频学习 (九) 从 0 ~ 1 开发一款 Android 端播放器(支持多协议网络拉流/本地文件)
- 音视频学习 (十) 基于 Nginx 搭建(rtmp、http)直播服务器
- 音视频学习 (十一) Android 端实现 rtmp 推流
- 音视频学习 (十二) 基于 FFmpeg + OpenSLES 实现音频万能播放器
- 音视频学习 (十三) Android 中通过 FFmpeg 命令对音视频编辑处理(已开源)