JNI的概念
Java Native Interface java本地接口
Native Native Language 本地语言 看操作系统使用什么语言开发的 那么这个语言就是本地语言
java c/c++ 通信的接口
Java 特点 一处编译到处运行 通过java虚拟机 把java代码和底层的操作系统隔离起来
c/c++ 平台相关性强
① java 想与硬件之间直接交互 不能直接交互 需要访问硬件的驱动 java需要调用C的代码
② java 运行的速度 比c要慢一些 高清视频回放 视频解码的库都是用c/c++去开发的
③ java 编译之后生成.class .class可以很容易的进行反编译 c编译之后生成机器码 机器码只能反汇编
金融软件
④ c语言有好多开源库 openCV ffmpeg vitamio
学习的目的 ①可以看懂android 所有的源码
② 有一些特定的需求 需要通过调用C去实现 需要使用JNI
Native c语言的基础 能看懂会调用
Interface NDK native develop kit
Java->C
c-> java
实际案例
c helloworld
#include <stdlib.h> // include 包含 类似java 的import
#include <stdio.h> // .h head C的头文件 std standard 标准的 stdlib 标准函数库 stdio.h 标准输入输出流
main(){ //c 程序的入口 和 java 的 public static void main(String args[])
printf("hello world!\n"); // System.out.print 向控制台输出一句话
system("pause"); //system 调用当前平台的指令
system("calc");
}
c 基本数据类型
java的基本数据类型 C的基本数据类型
boolean 没有boolean 0 false 非0 true
byte 没有byte
char 2 char 1
short 2 short
int 4 int
long 8 long 4
float 4 float
double 8 double
signed和unsigned 可以用来修饰整形变量 short int long char
signed 有符号 默认情况下都是有符号的
unsigned 无符号 使用了unsigned 来修饰整形变量 这个整形变量的最高位就是数值位 不再是符号位
C 输出函数
00000000 10111100 01100001 01001110
01100001 01001110
使用占位符的时候 一定要注意 类型和占位符之间一定要一一对应 如果用错了可能会出现问题
C 数组的声明 [] 一定要放到变量名字的后面
char str[]
#include <stdlib.h> // include 包含 类似java 的import
#include <stdio.h> // .h head C的头文件 std standard 标准的 stdlib 标准函数库 stdio.h 标准输入输出流
/**
%d - int
%ld – long int
%lld - long long
%hd – 短整型 short
%c - char
%f - float
%lf – double
%u – 无符号数
%x – 十六进制输出 int 或者long int 或者short int
%o - 八进制输出
%s – 字符串
*/
main(){
char c = 'a';
short s = 1234;
int i = 12345678;
long l = 1234567890;
float f = 3.14;
double d = 3.1415926;
printf("c = %c\n",c);
printf("s = %hd\n",s);
printf("i = %d\n",i);
printf("l = %ld\n",l);
printf("f = %.2f\n",f); //输出小数的时候默认显示6位有效数字 控制有效数字的位数 %.xf %.xlf
printf("d = %.7lf\n",d);
printf("i = %#x\n",i);
printf("i = %#o\n",i); // %#x %#o 带前缀输出8进制数 和16进制数
//java 字符串 string c的字符串实际上就是字符的数组 字符数组结束的标记就是 '\0'
char str[] = {'a','b','c','d','e','\0'};
char str1[] ="你好";
printf("str = %s\n",str1);
system("pause");
}
C 输入函数
#include <stdlib.h> // include 包含 类似java 的import
#include <stdio.h> // .h head C的头文件 std standard 标准的 stdlib 标准函数库 stdio.h 标准输入输出流
main(){
int count;
printf("请输入班级的人数:");
scanf("%d",&count); //& 取地址符 把 count这个变量的地址取出来 用户的输入会保存到count变量中
printf("班级的人数为:%d\n",count);
printf("count的地址:%d\n",&count);
char name[2];
printf("name的地址:%d\n",&name);
printf("请输入班级的名字:");
scanf("%s",&name);
printf("班级的人数是:%d\n班级的名字是:%s\n",count,name); //C数组不检查越界
system("pause");
}
内存地址的概念
内存的最小单位 byte 8位二进制数
内存要使用的时候 一定得对每一个byte进行编号 只有编号之后才能使用
32位系统 xp /win7 地址线32位 4G的内存
64位系统
C 的指针 ☆☆☆☆☆
#include <stdlib.h> // include 包含 类似java 的import
#include <stdio.h> // .h head C的头文件 std standard 标准的 stdlib 标准函数库 stdio.h 标准输入输出流
// 类型 * 变量名 pointer
main(){
int i = 456; // 这一行执行之后 会在内存中给变量i分配一块内存空间 这块内存的地址就是 0X24fe44
int* p = &i;
printf("p = %#x\n",p);
printf("i的地址%#x\n",&i);
printf("*p = %d\n",*p);
*p=789;
printf("i = %d\n",i);
system("pause");
}
int i = 123; int* p = &i;
p *p &p
C指针的常见错误
#include <stdlib.h> // include 包含 类似java 的import
#include <stdio.h> // .h head C的头文件 std standard 标准的 stdlib 标准函数库 stdio.h 标准输入输出流
//要避免野指针 在使用指针变量做赋值操作之前, 用自己程序中的变量的地址为指针变量赋初始值
//指针变量的类型要对应起来 int类型的变量地址 通过int类型的指针变量保存 double类型的变量地址 通过double类型的指针变量保存
main(){
int i;
int* p = &i; //野指针 指针变量声明之后没有赋初始值 直接对这个指针指向的地址做赋值的操作
printf("p = %#x\n",p);
*p = 1234;
double* p2 = &i;
printf("*p2 = %lf", *p2);
system("pause");
}
C 指针的练习
交换两个数的值
值传递 调用函数/方法的时候 传到方法中的是变量的值 值传递
引用传递 调用函数/方法的时候 传到方法中的也是数值 只不过这个值是一个地址值 引用传递
交换两个数
#include <stdlib.h> // include 包含 类似java 的import
#include <stdio.h> // .h head C的头文件 std standard 标准的 stdlib 标准函数库 stdio.h 标准输入输出流
void swap(int i, int j){
int temp = i;
i = j;
j = temp;
}
void swap2(int* p, int* p2){
int temp = *p;
*p = *p2;
*p2 = temp;
}
main(){
int i = 123;
int j = 456;
// int temp = i;
// i = j;
// j = temp;
// swap(i,j);
swap2(&i,&j);
printf("i = %d,j= %d\n",i,j);
system("pause");
}
返回多个值
void function(int* p, int* q){
*p *= 2;
*q *= 2;
}
main(){
int i = 123;
int j = 456;
function(&i,&j);
printf("i = %d,j = %d\n",i,j);
system("pause");
}
C 数组 和指针之间的关系
java的数组 是一块连续的内存空间
#include <stdlib.h> // include 包含 类似java 的import
#include <stdio.h> // .h head C的头文件 std standard 标准的 stdlib 标准函数库 stdio.h 标准输入输出流
// 表示地址的时候一般用十六进制来表示
main(){
// char array[] = {'a','b','c','d','e'};
int array[] = {1,2,3,4,15};
printf("array[0]的地址%#x\n",&array[0]);
printf("array[1]的地址%#x\n",&array[1]);
printf("array[2]的地址%#x\n",&array[2]);
printf("array[3]的地址%#x\n",&array[3]);
printf("array[4]的地址%#x\n",&array[4]);
// char* p= &array[0];
printf("array的地址%#x\n",&array);//数组的名字的地址 实际就是第一个元素的地址 也就是这个数组的首地址
// char* p = &array;
double* p = &array;
// printf("array[0] = %c\n",*(p+0));
// printf("array[1] = %c\n",*(p+1));
// printf("array[2] = %c\n",*(p+2));
// printf("array[3] = %c\n",*(p+3));
// printf("array[4] = %c\n",*(p+4));
printf("array[0] = %d\n",*(p+0));
printf("array[1] = %d\n",*(p+1));
printf("array[2] = %d\n",*(p+2));
printf("array[3] = %d\n",*(p+3));
printf("array[4] = %d\n",*(p+4));
printf("p+0= %#x\n",p+0);
printf("p+1= %#x\n",p+1);
printf("p+2= %#x\n",p+2);
printf("p+3= %#x\n",p+3);
printf("p+4= %#x\n",p+4);
//数组的首地址 也就是第一个元素的地址 也是数组变量名字获取的地址
//获取到数组的首地址之后 可以通过指针变量 遍历整个数组
//指针的位移运算 给指针 p+1 p+2 指针的位移运算 指针变量每+1 移动的字节数跟指针变量的类型有关
// int 类型指针 p+1 会移动4个字节 char* p p+1之后 移动1个字节 shortr* p p+1之后 移动2个字节 double* p p+1之后 移动8个字节
system("pause");
}
C的字符串的最常用的声明方式
#include <stdlib.h> // include 包含 类似java 的import
#include <stdio.h> // .h head C的头文件 std standard 标准的 stdlib 标准函数库 stdio.h 标准输入输出流
main(){
char str[] = {'a','b','c','d','e','\0'}; // c字符串 char类型的数组
char str2[] ="abcde";
//printf("str的值%#x\n",&str);
char* str3 = "你好"; // char* 类似于java的 string
printf("%s\n",str3);
printf("%#x\n",str3);
system("pause");
}
C指针变量的长度
C 的多级指针
用2级指针保存1级指针的地址
用n级指针 保存 n-1级指针的地址
main(){
int i = 123;
int* p = &i;
int** p2 = &p;
int*** p3 = &p2;
***p3= 456;
printf("i = %d\n",i);
system("pause");
}
main函数中 获取子函数临时变量的地址
void function(float** q){
float i = 123.4;
*q = &i;
printf("i的地址%#x\n",&i);
}
main(){
float* p;
function(&p);
printf("p = %#x\n",p);
system("pause");
}
静态内存分配和动态内存分配
静态内存分配 栈内存 大小固定 高地址向低地址扩展 栈内存的分配和回收是系统控制
int* function1(){
int array[] = {1,2,3,4,5};
printf("array的地址%#x\n",array);
return &array;
}
int* function2(){
int array2[] = {15,4,3,2,1};
printf("array2的地址%#x\n",array2);
return &array2;
}
main(){
int* p = function1();
function2();
printf("*(p+0)= %d,*(p+1)= %d,*(p+2)= %d,*(p+3)= %d,*(p+4)= %d\n",*(p+0),*(p+1),*(p+2),*(p+3),*(p+4));
printf("*(p+0)= %d,*(p+1)= %d,*(p+2)= %d,*(p+3)= %d,*(p+4)= %d\n",*(p+0),*(p+1),*(p+2),*(p+3),*(p+4));
system("pause");
}
C 的结构体☆☆☆☆☆
C 的联合体
C 的枚举
C 的自定义类型