C程序优化之路(二)
二.內存篇
?????? 在上一篇中我們講述了如何優化文件的讀寫,這一篇則主要講述對內存操作的優化,主要有數組的尋址,指針鏈表等,還有一些實用技巧。
I.優化數組的尋址
?????? 在編寫程序時,我們常常使用一個一維數組a[M×N]來模擬二維數組a[N][M],這個時候訪問a[]一維數組的時候:我們經常是這樣寫a[j×M+i](對于a[j][i])。這樣寫當然是無可置疑的,但是顯然每個尋址語句j×M+i都要進行一次乘法運算。現在再讓我們看看二維數值的尋址,說到這里我們不得不深入到C編譯器在申請二維數組和一維數組的內部細節上――實際在申請二位數組和一維數組,編譯器的處理是不一樣的,申請一個a[N][M]的數組要比申請一個a[M×N]的數組占用的空間大!二維數組的結構是分為兩部分的:
① 是一個指針數組,存儲的是每一行的起始地址,這也就是為什么在a[N][M]中,a[j]是一個指針而不是a[j][0]數據的原因。
② 是真正的M×N的連續數據塊,這解釋了為什么一個二維數組可以象一維數組那樣尋址的原因。(即a[j][i]等同于(a[0])[j×M+i])
清楚了這些,我們就可以知道二維數組要比(模擬該二維數組的)一維數組尋址效率高。因為a[j][i]的尋址僅僅是訪問指針數組得到j行的地址,然后再+i,是沒有乘法運算的!
??? 所以,在處理一維數組的時候,我們常常采用下面的優化辦法:(偽碼例子)
??? int a[M*N];
??? int *b=a;
??? for(…)
??? {
??????? b[…]=…;
??????? …………
??????? b[…]=…;
??????? b+=M;
??? }
這個是遍歷訪問數組的一個優化例子,每次b+=M就使得b更新為下一行的頭指針。當然如果你愿意的話,可以自己定義一個數組指針來存儲每一行的起始地址。然后按照二維數組的尋址辦法來處理一維數組。不過,在這里我建議你干脆就直接申請一個二維數組比較的好。下面是動態申請和釋放一個二維數組的C代碼。
int get_mem2Dint(int ***array2D, int rows, int columns)???? //h.263源代碼
{
??? int i;
??? if((*array2D?= (int**)calloc(rows, sizeof(int*))) == NULL) no_mem_exit(1);
??? if(((*array2D)[0] = (int* )calloc(rows*columns,sizeof(int ))) == NULL) no_mem_exit(1);
for(i=1 ; i<rows ; i++)
??????? (*array2D)[i] =? (*array2D)[i-1] + columns? ;
return rows*columns*sizeof(int);
}
void free_mem2D(byte **array2D)
{
??? if (array2D)
??? {
??? ??? if (array2D[0])
??????????? free (array2D[0]);
??????? else
??????????? error ("free_mem2D: trying to free unused memory",100);
??????? free (array2D);
? ? }
??? else
??? {
??? ??? error ("free_mem2D: trying to free unused memory",100);
??? }
}
順便說一下,如果你的數組尋址有一個偏移量的話,不要寫為a[x+offset],而應該為?b=a+offset,然后訪問b[x]。
不過,如果你不是處理對速度有特別要求的程序的話,這樣的優化也就不必要了。記住,如果編普通程序的話,可讀性和可移值性是第一位的。
II.從負數開始的數組
?????? 在編程的時候,你是不是經常要處理邊界問題呢?在處理邊界問題的時候,經常下標是從負數開始的,通常我們的處理是將邊界處理分離出來,單獨用額外的代碼寫。那么當你知道如何使用從負數開始的數組的時候,邊界處理就方便多了。下面是靜態使用一個從-1開始的數組:
int a[M];
int *pa=a+1;
現在如果你使用pa訪問a的時候就是從-1到M-2了,就是這么簡單。(如果你動態申請a的話,free(a)可不要free(pa)因為pa不是數組的頭地址)
III.我們需要鏈表嗎
?????? 相信大家在學習《數據結構》的時候,對鏈表是相當熟悉了,所以我看有人在編寫一些耗時算法的時候,也采用了鏈表的形式。這樣編寫當然對內存的占用(似乎)少了,可是速度呢?如果你測試:申請并遍歷10000個元素鏈表的時間與遍歷相同元素的數組的時間,你就會發現時間相差了百倍!(以前測試過一個算法,用鏈表是1分鐘,用數組是4秒鐘)。所以這里我的建議是:在編寫耗時大的代碼時,盡可能不要采用鏈表!
?????? 其實實際上采用鏈表并不能真正節省內存,在編寫很多算法的時候,我們是知道要占用多少內存的(至少也知道個大概),那么與其用鏈表一點點的消耗內存,不如用數組一步就把內存占用。采用鏈表的形式一定是在元素比較少,或者該部分基本不耗時的情況下。
(我估計鏈表主要慢是慢在它是一步步申請內存的,如果能夠象數組一樣分配一個大內存塊的話,應該也不怎么耗時,這個沒有具體測試過。僅僅是猜想 :P)
轉載于:https://www.cnblogs.com/huaping-audio/archive/2008/09/11/1289454.html
總結
以上是生活随笔為你收集整理的C程序优化之路(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VOIP语音测试
- 下一篇: 软件质量保证基本知识加复习建议