### 结构体
* 结构体中的属性长度会被自动补齐,这是为了方便指针位移运算
* 结构体中不能定义函数,可以定义函数指针
* 程序运行时,函数也是保存在内存中的,也有一个地址
* 结构体中只能定义变量
* 函数指针其实也是变量,它是指针变量
* 函数指针的定义 返回值类型(*变量名)(接收的参数);
* 函数指针的赋值: 函数指针只能指向跟它返回值和接收的参数相同的函数
代码
```
#include<stdio.h>
#include<stdlib.h>
/**
c结构体 类似java的class struct来声明c的结构体
结构体的大小大于等于结构体中每一变量的占字节数的和
结构体的大小是最大的那个变量所占字节数的整数倍,实际上是将不同类型的成员对齐后再相加
C结构体中不能定义函数,但是通过函数指针也可以解决问题,函数指针指向具体的函数,调用时通过结构体调用函数指针,就可以实现在结构体中拥有函数的需求
函数指针的定义 返回值(*函数指针变量名字)(返回值);
-> 间接引用运算符,指向结构体成员运算符,类似于结构成员运算符".";都是用来访问结构体成员的,
只不过使用对象不同,用指针来访问结构体成员,就要用"->";
假如使用结构体变量来访问结构体成员,就需要结构体成员运算符"."
*/
void study(){
printf("good good study!\n");
}
typedef struct Student{
int age; //8
int score; // 4
char sex; //1
void(*studypointer)();//函数指针studypointer
} stud;//typedef为结构体取个别名stud它的作用和struct Student相同,也可以说是简化为stud
main(){
stud stu = {18,100,'f'};
stu.studypointer = &study;
stu.studypointer();
struct Student* stuPointer = &stu;//结构体指针 struct Student* (类型后面加上“*”符号)
printf("*stuPointer.age = %d\n",(*stuPointer).age);
(*stuPointer).sex ='m';
printf("stu.sex = %c\n",stu.sex);
printf("stuPointer->age = %d\n",stuPointer->age);
//printf("stu.age = %hd\n",stu.age);
//printf("stu.score = %d\n",stu.score);
//printf("stu.sex = %c\n",stu.sex);
// printf("结构体student占%d个字节\n",sizeof(stu));
system("pause");
}
```
输出结果
~~~
good good study!
*stuPointer.age = 18
stu.sex = m
stuPointer->age = 18
~~~
#### 零起点学通C语言摘要 ####
**结构体,顾名思义就是多个变量共用一块内存,其实就是用户自定义的数据类型,这个数据类型通常由多个类型的数据成员组成**
```
#include <stdio.h>
int main()
{
struct book //图书 struct是关键字
{
int num; //编号
char name[20]; //书名
float price; //价格
int amount; //数量
};
return 0;
}
```
**结构变量**
struct book Jack ,struct是关键字,用来说明这是一个结构体类型,而book则说明该结构体类型的名字为book,Jack是通过book定义的结构变量,Jack必须通过点运算符访问它的各个成员,然后利用它的成员来保存数据,“.”成为点运算符或者结构成员运算符,优先级高于赋值运算符
**结构变量的多种定义方式**
```
#include <stdio.h>
#include <string.h>
//一、先声明结构体类型再定义变量。
//先声明结构体类型:
struct employees //员工
{
char name[20]; //姓名
float pay; //工资
};
//再定义结构变量:
struct employees Jane;
//也可以一次性定义多个结构变量,每两个结构变量之间用逗号隔开:
struct employees John,Rose,Mick;
//该语句一次性定义了3个结构变量--John、Rose和Mick。
int main()
{
//二、声明结构体类型的同时定义变量。
struct employees_a //员工
{
char name[20]; //姓名
float pay; //工资
} Jame,Tom,Kity;
//右大括号的后面是定义的变量,可以定义一个,
//也可以定义多个,假如定义多个,用逗号将它们隔开。
//以下为结构变量赋值
strcpy(Jame.name,"Jack"); //姓名为Jack
Jame.pay=3278.60f; //工资为3278.60
strcpy(Tom.name,"Tom"); //姓名为Tom
Tom.pay=3578.60f; //工资为3578.60
strcpy(Kity.name,"Kity"); //姓名为Kity
Kity.pay=3978.60f; //工资为3978.60
//三、省略结构体类型的名称。
/*
struct //员工
{
char name[20]; //姓名
float pay; //工资
}LiMing,Liu,Cheng;
//struct后面可省略掉结构体的名称。
//以下为结构变量赋值
strcpy(LiMing.name,"Jack"); //姓名为LiMing
LiMing.pay=3278.60f; //工资为3278.60
strcpy(Liu.name,"Liu"); //姓名为Liu
Liu.pay=3578.60f; //工资为3578.60
strcpy(Cheng.name,"Cheng"); //姓名为Cheng
Cheng.pay=3978.60f; //工资为3978.60
*/
return 0;
}
```
**结构变量的初始化**
```
/*单行初始化
#include <stdio.h>
struct //员工
{
char name[20];//姓名
float pay; //工资
} one={"李磊",3452.86f},two={"赵安",4562.50f};//可以直接对这2个结构变量进行初始化
int main()
{
printf("%s的工资为:%.2f\n",one.name,one.pay);
printf("%s的工资为:%.2f\n",two.name,two.pay);
return 0;
}
*/
//分行初始化 结构变量很多,则需要给结构体类型取个名字,然后在定义结构变量的时候进行初始化
#include <stdio.h>
struct employees //员工
{
char name[20]; //姓名
float pay; //工资
};
int main()
{
struct employees LiLei={"李磊",3452.86f};//定义LiLei的时候进行初始化
struct employees ZhaoAn={"赵安",4562.50f};
printf("%s的工资为:%.2f\n",LiLei.name,LiLei.pay);
printf("%s的工资为:%.2f\n",ZhaoAn.name,ZhaoAn.pay);
return 0;
}
```
**结构变量的赋值**
```
#include <stdio.h>
struct employees //员工
{
char name[20]; //姓名
float pay; //工资
};
int main()
{
struct employees ZhaoAn={"李磊",3452.86f};
struct employees LiLei={"赵安",4562.50f};//初始化的时候出错,数据保存ZhaoAn和LiLei的数据保存错误
struct employees three;//定义第三个结构体暴力,用于交换ZhaoAn和LiLei的值
three=ZhaoAn;
ZhaoAn=LiLei;
LiLei=three;
printf("%s的工资为:%.2f\n",ZhaoAn.name,ZhaoAn.pay);
printf("%s的工资为:%.2f\n",LiLei.name,LiLei.pay);
return 0;
}
```
**结构体数组**
由多个结构变量组成的数组叫做结构体数组
```
#include <stdio.h>
#define N 10
struct employees //员工
{
char name[20]; //姓名
float pay; //工资
};
int main()
{
struct employees em[N];//利用结构体类型employees定义一个结构体数组em,它有N个元素,每个元素都是一个结构体变量
int i;
for (i=0;i<N;i++)
{
printf("请输入第%d名员工的姓名:",i+1);
scanf("%s",&em[i].name);//访问结构体中的元素通过下标
printf("请输入第%d名员工的工资:",i+1);
scanf("%f",&em[i].pay);
}
printf("列出所有员工的工资\n");
for (i=0;i<N;i++)
{
printf("%s的工资为:%.2f\n",em[i].name,em[i].pay);
}
return 0;
}
```
**结构体的嵌套**
一个结构体变量可以嵌套在另一个结构体中
```
#include <stdio.h>
struct date //日期
{
int year; //年
int month; //月
int day; //日
};
struct employees //员工
{
char name[20]; //姓名
float pay; //工资
struct date joinDate; //参加工作时间
};
int main()
{
struct employees em; //创建一个员工em
em.joinDate.year=1978; //该员工1978年参加工作
em.joinDate.month=12; //参加工作的月份是12
em.joinDate.day=30; //参加工作的日期是30
return 0;
}
```
**结构体的大小**
**对齐规则,结构体中最大成员的字节必须是其它成员的整数倍,假如不够则补齐**
~~~
#include<stdio.h>
struct stu
{
int i;//4
char j;//1
float c;//4
};
struct stu1
{
char j;//1
int i;//4
double c;//8
};
struct stu2
{
char j;//1
int i;//4
double c;//8
char k;//1
};
struct stu3
{
char j;//1
int i;//4
double c;//8
char k;//1
char m;
char o;
char p;
char q;
char r;
char s;
char t;
};
struct stu4
{
char j;//1
int i;//4
double c;//8
char k;
char m;
char o;
char p;
char q;
char r;
char s;
char t;
char u;
};
int main()
{
struct stu s1={1,'c',198.12f};
int n=sizeof(s1);
printf("%d\n",n);//12
printf("%d\n",sizeof(struct stu1));//16
printf("%d\n",sizeof(struct stu2));//24
printf("%d\n",sizeof(struct stu3));//24
printf("%d\n",sizeof(struct stu4));//32
return 0;
}
~~~
输出结果
~~~
12
16
24
24
32
~~~
- **struct stu 中int占用4个字节, char占用1个字节,float占用4个字节,将所有成员都对齐排放,将char与int对齐,这样char也占用4个字节,float同样占用4个字节,这样总共就是12个字节**
- **struct stu1中int占用4个字节, char占用1个字节,double则占用8个字节,正好是前面2个成员的整数倍,因此第三个成员占用字节数保持8个不变,将char与int对齐,这样char也占用4个字节,将3个成员所占字节数相加:4+4+8=16**
- **struct stu2中int占用4个字节, char占用1个字节,double则占用8个字节,因为第四个成员是char类型,占用1个字节,为了与第三个成员对齐,也给他分配8个字节,假如double后面有8个char型成员,则这8个char型成员将挤在一起。结构体大小为4+4+8+8=24**
- **struct stu3 中double后面有8个char型成员,则这8个char型成员将挤在一起,结构体大小为4+4+8+8=24**
- **struct stu4 中double后面有9个char型成员,前8个char挤在一起,合占8个字节,第九个char型成员,结构体大小补齐为8则,结构体大小是4+4+8+8+8=32**
#### 结构体与指针 ####
可以通过取地址符来获取结构体变量的地址,然后将该地址交给指针来保存,那么只要指针的值不被修改,就可以找到结构体变量
#### 指向结构体变量的指针
```
#include<stdio.h>
#include<string.h>
struct book
{
char name[10];
float price;
};
int main()
{
struct book d1;
struct book *p;
p=&d1;//取出结构体变量1的地址赋给指针p,现在p指向结构体变量d1
strcpy(p->name,"呼啸山庄");//调用strcpy函数,将"呼啸山庄"复制到指向的结构体变量d1的成员ame中
p->price=11.80f;
printf("书名:%s\t价格:%.2f\n",p->name,p->price);
return 0;
}
```
#### 指向结构体数组的指针
一个指针保存了结构体数组的地址,就可称为指向结构推为数组的指针
```
#include<stdio.h>
#include<string.h>
struct book
{
char name[10];
float price;
};
int main()
{
struct book mybook[3]={
{"呼啸山庄",11.80f},
{"三国演义",46.50f},
{"百年孤独",40.10f}
};
struct book *p;
int i;
p=mybook;
/**将结构体数组名复制给指针p,由于数组名即数组的地址,
而数组的地址又是该数组第一个元素的地址,即将第一个结构体变量的地址复制给了指针p
*/
for (i=0;i<3;i++)//数组mybook共保存了3个结构体变量,因此循环3次
{
printf("书名:%s\t价格:%.2f\n",p->name,p->price);
p++;
}
return 0;
}
```
>**指向结构体数组的指针每自加一次,是在原有地址的基础上再加上一个元素(结构体变量)所占用的字节数,因此会指向下一个结构体变量**
- 前言
- 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 命令对音视频编辑处理(已开源)