編輯:關於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申請堆內存
#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,暫時學到這裡!!
本文詳細描述了如何實現如下圖中的微信啟動界面. 該類啟動界面的特點是在整個Application的生命周期裡, 它只會出現在第一次進入應用時, 即便按回退鍵到桌面之後.
一、加載過程動態展示動畫在APP的研發中,加載過程用動畫更改時間的消耗,增強用戶體驗。而有個更精細的加載過程動畫,會不斷從細節優化APP的體驗。且隨著APP與服務器交互的
在平時開發過程中,MD5加密是一個比較常用的算法,最常見的使用場景就是在帳號注冊時,用戶輸入的密碼經md5加密後,傳輸至服務器保存起來。雖然md5加密經常用,但是md5的
隨著6月份google的Android N preview 4版本的發布,筆者也借著東風在N6P上體驗了一把新系統,試玩之後認為有幾點新的感受特記錄之。1.分屏多任務進入