JNI


android
JNI開發java

what 什麼是JNIandroid

  • JNI java native interface native本地 java本地接口
  • 經過JNI能夠實現java和本地代碼之間相互調用
  • jni能夠看作是翻譯 實際上就是一套協議

why 爲何要用JNIc++

  • Java 一處編譯處處運行 
  • ①java運行在虛擬機上 沒法直接操做硬件 JNI能夠擴展java虛擬機的能力 讓java代碼能夠調用驅動
  • ②java是解釋型語言 運行效率相對較低 C/C++的效率要高不少 經過jni把耗時操做方法C/C++能夠提升java運行效率
  • ③ java代碼編譯成的.class 文件安全性較差, 能夠經過jni 把重要的業務邏輯放到c/c++去實現,c/c++反編譯比較困難 安全性較高
  • C歷史悠久 1972年C 經過JNI能夠調用優秀的C開源類庫

How 怎麼用JNI程序員

  • java
  • c/c++ 能看懂 會調用
  • JNI開發流程 NDK native develop kit

C基本語法windows

CHelloWorld數組

#include<stdio.h>    // 至關於 java的import .h c的頭文件 stdio.h standard io 標準輸入輸出

#include<stdlib.h>   // stdlib standard library 標準函數庫    java.lang

/**

*/

main(){    // public static void main(String[] args)

       printf("helloworld!\n");  //System.out.println();   "\n"換行符

       system("javac Hello.java");

       system("java Hello");

       system("notepad");

       system("pause"); //system執行windows的系統命令

       }

 

C的基本數據類型安全

  • java基本數據類型 C基本數據類型 
    boolean 1 
    byte 1 
    char 2 char 1個字節 
    short 2 short 2 
    int 4 int 4 
    long 8 long 4 
    float 4 float 4 
    double 8 double 8

char, int, float, double, long, short, signed, unsigned, void 
* signed 有符號數 最高位是符號位 能夠表示負數 可是表示的最大值相對要小 
* unsigned 無符號數 最高位是數值位 不能夠表示負數 表示的最大值相對要大 
* signed unsigned 只能用來修飾整形變量 char short int long 
* C沒有 boolean byte C用0和非0表示false true函數

C的輸出函數 printf學習

%d  -  intspa

%ld – long int

%lld - long long

%hd – 短整型

%c  - char

%f -  float

%lf – double

%u – 無符號數

%x – 十六進制輸出 int 或者long int 或者short int

%o -  八進制輸出

%s – 字符串

* printf(「含有佔位符的要輸出的字符串」,…..); 
* 佔位符不要亂用 要選擇正確的對應類型 不然可能會損失精度 
* C字符串 
* C沒有String類型 C的字符串實際就是字符數組 
* C數組定義 [ ]只能再變量名以後 
* C字符串兩種定義方式

        char str[] = {'h','e','l','l','o','\0'};//注意'\0'字符串結束符

        char str[] = "你好"; //這種定義方式不用寫結束符 能夠表示漢字

 

C的輸入函數

  • scanf(「佔位符」, &地址);
  • & 取地址符
  • C字符串不檢查下標越界 使用時要注意

內存地址的概念

  • 聲明一個變量,就會當即爲這個變量申請內存,必定會有一個對應的內存地址
  • 沒有地址的內存是沒法使用的
  • 內存的每個字節都有一個對應的地址
  • 內存地址用一個16進制數來表示
  • 32位操做系統最大能夠支持4G內存 
  • 32位系統的地址總線爲32位,也就是說系統有2^32個數字能夠分配給內存做爲地址使用

指針概念 **

        int i = 123;

       //通常計算機中用16進制數來表示一個內存地址

       printf("%#x\n",&i);

       //int* int類型的指針變量  pointer指針  指針變量只能用來保存內存地址

       //用取地址符&i 把變量i的地址取出來 用指針變量pointer 保存了起來

       //此時咱們能夠說 指針pointer指向了 i的地址

       int* pointer = &i;  

       printf("pointer的值 = %#x\n",pointer);

       printf("*pointer的值%d\n",*pointer);

       *pointer = 456;

       printf("i的值是%d\n",i);

       system("pause");

 

* 指針常見錯誤 
* 聲明瞭指針變量後 未初始化直接經過*p 進行賦值操做 運行時會報錯 
* * 未初始化直接使用的指針稱爲野指針 
* 指針類型錯誤 如int* p 指向了double類型的地址, 經過指針進行讀取操做時,讀取值會出錯

指針的練習

  • 值傳遞和引用傳遞(交換兩個數的值)
  • 引用傳遞本質是把地址傳遞過去
  • 全部傳遞其實本質都是值傳遞,引用傳遞其實也是傳遞一個值,可是這個值是一個內存地址
    • void swap(int* p, int* p2){
          int temp = *p;
          *p = *p2;
          *p2 = temp;
      }
      main(){
          int i = 123;
          int j = 456;
          //將i, j的地址傳遞過去
          swap(&i,&j);
          printf("i = %d, j = %d", i, j);
      }

       

    • 返回多個值
    • 把地址做爲參數傳入函數中,當函數執行完畢時,參數的值就已經被修改了
      • "*" 號幾種含義      
      • int* p 聲明一個int類型的指針變量
      • *p   對p中保存的內存地址對應的內存進行操做
      • i * j   乘法運算

數組和指針的關係

  • 數組佔用的內存空間是連續的
  • 數組名字變量保存的是第0個元素地址,也就是首地址
  • 能夠經過一個指針變量來保存一個數組的首地址
  • 拿到了首地址以後 就能夠經過指針的位移運算 遍歷數組的每個元素
  • *(p + 1):指針位移一個單位,一個單位是多少個字節,取決於指針的類型
  • 區分指針類型是爲了指針位移運算方便
    • main(){ 
        //char array[] ={'a','b','c','d','\0'};
        int array[] = {1,2,3,4,5};
        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的地址是%#x\n",&array);
       
        char* p = &array[0];
        //int* p = &array;
        //char* p = &array;
        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+0) = %c\n",*(p+0));
        printf("*(p+1) = %c\n",*(p+1));
        printf("*(p+2) = %c\n",*(p+2));
        printf("*(p+3) = %c\n",*(p+3));
        */
        printf("*(p+0) = %d\n",*(p+0));
        printf("*(p+1) = %d\n",*(p+1));
        printf("*(p+2) = %d\n",*(p+2));
        printf("*(p+3) = %d\n",*(p+3));
        printf("*(p+3) = %d\n",*(p+4));
       
        system("pause");
         }

       

指針的長度

  • 無論變量的類型是什麼,它的內存地址的長度必定是相同的
  • 32位環境下,內存地址長度都是4個字節,因此指針變量長度只需4個字節便可
  • 64位環境下 指針變量的長度都是8個字節
    • main(){ 
        int* p;
        double* p1;
        printf("p佔%d個字節\n",sizeof p);
        printf("p1佔%d個字節\n",sizeof p1);
        system("pause");
         } 

       

多級指針

  • int* p; int 類型的一級指針 int** p2; int 類型的二級指針
  • 二級指針變量只能保存一級指針變量的地址
  • 有幾個* 就是幾級指針 int*** 三級指針
  • 經過int類型三級指針 操做int類型變量的值 ***p
    •    
       int i = 123;
          //int類型一級指針
          int* p = &i;
          //int 類型 二級指針 二級指針只能保存一級指針的地址
          int** p2 = &p;
          //int 類型 三級指針  三級指針只能保存二級指針的地址
          int*** p3 = &p2;
          //經過p3 取出 i的值
          printf("***p3 = %d\n", ***p3);

       

    • 多級指針案例 取出子函數中臨時變量的地址
    • 實際上也是一個值傳遞引用傳遞的問題
    • 就是要經過子函數修改main函數中變量p的值 要用引用傳遞把p的地址傳過去
      • void function(int** p1){
         int i = 123;
         *p1 = &i;
         printf("i的地址%#x\n",&i);
         }
        main(){ 
          int* p;
          function(&p);
           printf("*p = %d\n",*p);
          printf("p的值%#x\n",p);
         
          system("pause");
           }

         

堆棧概念靜態內存分配動態內存分配

  • 棧內存 
  • 系統自動分配
  • 系統自動銷燬
  • 連續的內存區域
  • 向低地址擴展
  • 大小固定
  • 棧上分配的內存稱爲靜態內存
  • 靜態內存分配 
  • 子函數執行完,子函數中的全部局部變量都會被銷燬,內存釋放,但內存地址不可能被銷燬,只是地址上的值沒了
  • 堆內存 
  • 程序員手動分配 
  • java:new
  • c:malloc
  • 空間不連續
  • 大小取決於系統的虛擬內存
  • C:程序員手動回收free
  • java:自動回收
  • 堆上分配的內存稱爲動態內存

結構體

  • 結構體中的屬性長度會被自動補齊,這是爲了方便指針位移運算
  • 結構體的大小 
  • ① 大於等於全部元素的和
  • ② 是最大的元素大小的整數倍
  • 結構體中不能定義函數,能夠定義函數指針
  • 程序運行時,函數也是保存在內存中的,也有一個地址
  • 結構體中只能定義變量
  • 函數指針其實也是變量,它是指針變量
  • 函數指針的定義 返回值類型(*變量名)(接收的參數);
  • 函數指針的賦值: 函數指針只能指向跟它返回值和接收的參數相同的函數
    • typedef struct Student{
            double score;  //8
            short age;    //2
            char sex;     //1
            //聲明瞭一個函數指針study
           void (*study)();
            } s;
       void study(){
                 printf("好好學習,每天向上!\n");
                 }
      main(){ 
         s stu = {99.9,18,'f',&study};
         stu.age = 20;
         stu.study();
         printf("stu.score = %.1lf\n",stu.score);
         printf("stu.age = %hd\n",stu.age);
         printf("stu.sex = %c\n",stu.sex);
         printf("stu的大小佔%d個字節\n",sizeof(stu));
         //聲明瞭一個結構體指針p 來保存結構體變量stu的地址
         struct Student* p = &stu;
         (*p).age = 30;
         //-> 間接引用運算符
         p->age = 40;
         p->study();
          printf("stu.age = %hd\n",stu.age);
            system("pause");
             }

       

聯合體

  • 長度等於聯合體中定義的變量當中最長的那個
  • 聯合體只能保存一個變量的值
  • 聯合體共用同一塊內存

枚舉

  • 枚舉的做用 規定了 enum weekday 的取值範圍 只能取枚舉值
  • 默認枚舉值從0開始 每一個元素依次+1

結構體的練習

  • C面向過程的而語言 以函數爲中心
  • java面向對象的語言 以數據(對象爲中心)
    • #include<stdlib.h>  
      #include<stdio.h>  
       
      //給結構體struct Light 起別名 light
      typedef struct Light light;
      struct Light{
             //用來表示等開關的狀態
             int state;
             //聲明兩個函數指針
             //關燈的函數指針 經過函數修改light的狀態
             //要接收一個light的地址 因此形參爲light*類型
             void(*turnOff)(light*);
             //開燈的函數指針
             void(*turnON)(light*);
             };
      //關燈的函數
      void turnOff(light* l){
           //經過結構體的指針修改結構體的變量state
           l->state = 0;
           printf("關燈\n");
           }
      //開燈的函數
      void turnON(light* l){
           //經過結構體的指針修改結構體的變量state
           l->state = 1;
           printf("開燈\n");
           }
      //模仿一個構造方法 作兩件事兒 ① 申請一塊堆內存 ② 給結構體的成員賦初始值
      light* newLight(){
           //申請一塊堆內存 用來保存light這個結構體的實例
           light* led = (light*)malloc(sizeof(light));
           //初始化
           led->state = 0;
           //給函數指針turnOff賦初始值 使函數指針指向具體的函數
           led->turnOff = &turnOff;
           // 給函數指針turnON賦初始值 使函數指針指向具體的函數
           led->turnON = &turnON;
           return led;
           }
      main(){
             //調用模仿的構造方法 返回一個結構體Light的引用 
            light* led = newLight();
            //調用結構體中turnON開燈這個函數指針
            led->turnON(led);
            printf("led->state = %d\n",led->state);
            system("pause");
             }
相關文章
相關標籤/搜索