Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android For JNI(四)——C的數組,指針長度,堆內存和棧內存,malloc,學生管理系統

Android For JNI(四)——C的數組,指針長度,堆內存和棧內存,malloc,學生管理系統

編輯:關於Android編程

 

好幾天每寫JNI了,現在任務也越來越重了,工作的強度有點高,還有好幾個系列的博客要等著更新,幾本書還嗷嗷待哺的等著我去看,github上的兩個散漫的開源,基礎入門的視頻也在錄制,還要學習新的知識,
都是一種挑戰,不知道為何,最近懶散了,看來還得再加把勁,今天我們繼續延伸一下C的一些小知識

一.數組

C的數組和JAVA也是類似的,我們寫一段小程序

#include     
#include    

main(){ 

        char c [] ="lgl";           
       //打印 每個元素的地址 
        printf("%#x\n",&c[0]); 
        printf("%#x\n",&c[1]); a
        printf("%#x\n",&c[2]); 
        printf("%#x\n",&c[3]); 
        //讓窗口停留 
        int age ; 
        scanf("%d",&age);

   }

我們打印一下這個數組的每個元素的內存地址,會驚奇的發現內存地址是連續的

這裡寫圖片描述

我們繼續理解

  //打印C的地址
  printf("%#x\n",&c); 

我們打印C的地址

這裡寫圖片描述

得到的結論是第一個內存地址,由此我們歸納

數組的內存空間是連續的 數組變量保存的是第0個元素的地址
        //字符數組的地址,就是一個字符的地址 
        char* p = &c;

        printf("第0個元素的值%c\n",*(c + 0));
        printf("第0個元素的值%c\n",*(c + 1));
        printf("第0個元素的值%c\n",*(c + 2));

這裡,我們就可以拿到lgl這是哪個數了
當然,如果是int類型的話,就需要位移四個單位了

二.指針長度

指針我們可以存地址,我們要想知道他的長度有多長,我們就得去測試一下

#include     
#include    

main(){

      printf("int*的長度是%d\n",sizeof(int*));
      printf("double*的長度是%d\n",sizeof(double*));    
      //讓窗口停留 
      int age ; 
      scanf("%d",&age);
}

輸出的結果

這裡寫圖片描述

指針長度為4,因為32位的環境,內存長度為4,足夠了

三.堆內存和棧內存

JAVA也有類似的說法,我們定義一個變量,就在內存中開辟一個控件,那具體開辟在哪呢,這就要看我們的類型了,我這裡畫張圖,好理解一下

這裡寫圖片描述

在JAVA中,我們定義一個變量比如int i是在棧內存開辟控件,persion p 也是,但是我們new了之後,對象是在堆內存裡。在C中,我們沒有new,我們有一個申請內存的函數malloc,但是java也有其他的因果,比如我們寫個數組,其實k就在棧內存,但是數組對象卻在堆內存

堆和棧的區別:

1.申請方式

棧:
由系統自動分配.例如,聲明一個局部變量int b; 系統自動在棧中為b開辟空間.例如當在調用涵數時,需要保存的變量,最明顯的是在遞歸調用時,要系統自動分配一個棧的空間,後進先出的,而後又由系統釋放這個空間.
堆:
需要程序員自己申請,並指明大小,在c中用malloc函數
如char* p1 = (char*) malloc(10); //14byte
但是注意p1本身是在棧中的.

2 申請後系統的響應

棧:只要棧的剩余空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。
堆:首先應該知道操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時, 會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多余的那部分重新放入空閒鏈表中。

3.申請大小的限制

棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是2M(vc編譯選項中可以設置,其實就是一個STACK參數,缺省2M),如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。
堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。

4.申請效率的比較:

棧:由系統自動分配,速度較快。但程序員是無法控制的。
堆:由malloc/new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便.

5.堆和棧中的存儲內容

棧:在函數調用時,第一個進棧的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的地址,然後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧的,然後是函數中的局部變量。注意靜態變量是不入棧的。
當本次函數調用結束後,局部變量先出棧,然後是參數,最後棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。
堆:一般是在堆的頭部用一個字節存放堆的大小。堆中的具體內容有程序員安排。

6.內存的回收

棧上分配的內存,編譯器會自動收回;堆上分配的內存,要通過free來顯式地收回,否則會造成內存洩漏。
堆和棧的區別可以用如下的比喻來看出: \
使用棧就像我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等准備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。
使用堆就像是自己動手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。

四.malloc

既然了解了,那我們就來使用malloc申請堆內存

#include     
#include    

main(){             
       //比如存三個int  int是4位的  所以寫12 這12個字節的內存地址是連續的,
       //他返回 的是堆內存的首地址 
       int* p = malloc(3 * sizeof(int)); 

       //賦值
       *(p + 1) = 3; 
       //打印值 
        printf("%d\n",*(p+1));   // = 3?
        //打印地址
        printf("%#x\n",(p+1)); 
        //讓窗口停留 
        int age ; 
        scanf("%d",&age);
      }

我們輸出結果

這裡寫圖片描述

申請之後怎麼釋放呢?

    //釋放堆內存
    free(p); 

我們可以嘗試一下釋放

#include     
#include    

main(){             
       //比如存三個int  int是4位的  所以寫12 這12個字節的內存地址是連續的,
       //他返回 的是堆內存的首地址 
       int* p = malloc(3 * sizeof(int)); 

       //賦值
       *(p + 1) = 3; 
       //打印值 
        printf("%d\n",*(p+1));   // = 3?
        //打印地址
        printf("%#x\n",(p+1)); 

        //釋放堆內存
        free(p); 

        //打印值 
        printf("%d\n",*(p+1));   // = 3?
        //打印地址
        printf("%#x\n",(p+1)); 

        //讓窗口停留 
        int age ; 
        scanf("%d",&age);
      }



我們會發現,內存釋放了之後,值就變了,當然內存不可能被釋放,而且P一直指向的是棧內存

這裡寫圖片描述

五.後台管理系統

我們這裡寫個小例子,說起來這麼高大上,其實就是一段小程序,學號管理id小程序,我們玩玩

程序本身還是很簡單的,就是把前面幾篇的小知識柔和在了一起

#include     
#include    

main(){             
        printf("請輸入班級人數:");         

        int count ; 
        scanf("%d",&count);

        //有多少個人就有多少個學號 
        int i ;
        //申請堆內存 保存學號
        int* p = malloc(count * sizeof(int)); 

        for(i = 1; i <= count; i++){

           printf("請輸入第%d個學生的學號:",i);

              scanf("%d",(p + i - 1));      
    }

     // 打印所有的學號 
     for(i = 1; i <= count; i++){
           printf("第%d個學生的學號是%d\n",i,*(p+i-1)); 
       } 

       int age ; 
       scanf("%d",&age);

       system("pause");
}




運行一下就知道效果了

這裡寫圖片描述

當然,我們既然是管理系統,插入嘛,我們繼續往下寫
我們這裡會接觸到一個新的API,我們看下去

#include     
#include    

main(){             
        printf("請輸入班級人數:");         

        int count ; 
        scanf("%d",&count);

        //有多少個人就有多少個學號 
        int i ;
        //申請堆內存 保存學號
        int* p = malloc(count * sizeof(int)); 

        for(i = 1; i <= count; i++){

           printf("請輸入第%d個學生的學號:",i);

              scanf("%d",(p + i - 1));      
    }

    //插入 
    printf("請輸入要插入的人數:"); 
    int newCount;

    scanf("%d",&newCount);
    //重新申請堆內存 
    //在原有的內存中擴展新的空間 
    //當然,前提要確定可不可以擴展,如果內存被暫用,系統會自動分配內存 
    //新內存會把舊內存拷貝過去,並且釋放舊的內存 
    p = realloc(p,(count + newCount) * sizeof(int)); 

     for(i = count+1; i <= count+newCount; i++){

           printf("請輸入第%d個學生的學號:",i);

              scanf("%d",(p + i - 1));      
    }


     // 打印所有的學號 
     for(i = 1; i <= count + newCount; i++){
           printf("第%d個學生的學號是%d\n",i,*(p+i-1)); 
       } 

       int age ; 
       scanf("%d",&age);

       system("pause");
}




這裡注意的就是realloc了,注釋也很明了的解析了,我們運行一下

這裡寫圖片描述

OK,暫時學到這裡!!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved