sizeof獲取陣列長度
昨天開始看《演算法導論》這本書,第一個演算法就是(直接)插入排序,根據書裡給出的虛擬碼寫出了C語言程式碼,也根據自己的理解重新寫了一個。雖然實現了演算法的基本要求,但有些細節沒有處理好,今天就來完善一下。
在昨天實現的程式碼中,用來測試的陣列int array[] = {5,2,4,6,1,3};是固定的,如果要更換待排序陣列話,原來程式中的相關變數就會因為陣列長度的改變要做相應的改變。我想要的就是給定任意的陣列,在不修改任意程式碼的條件下實現插入排序。所以,核心問題就是怎麼獲取給定陣列中的元素個數。
自然而然想到的就是sizeof(C/C++中的一個操作符,其功能是返回一個物件或者型別所佔的記憶體位元組數)。
一、首先來看看怎麼獲取整數陣列的長度
sizeof的語法形式如下:
(1)sizeof( object ); // sizeof( 物件 );
(2)sizeof( type_name ); // sizeof( 型別 );
(3)sizeof object; // sizeof 物件;
個人喜歡使用sizeof()的形式,因為形式統一,而且可以避免引起混亂導致出錯。
假設有一給定陣列 int array[] = {5,2,4,6,1,3};
length為陣列array[]中的元素個數,那麼
上述三個表示式都能得到正確的結果,雖然表示式略有不同,但原理是相同的,即通過sizeof(array)獲取整個陣列所佔的記憶體位元組數,再通過sizeof(*array)或者sizeof(array[0])或者sizeof(int)來獲取每個元素所佔的位元組數,陣列所佔的位元組數除以每個元素所佔的位元組數就是該陣列的元素個數了。length = sizeof(array)/sizeof(*array); //表示式1 //length = sizeof(array)/sizeof(array[0]); //表示式2 //length = sizeof(array)/sizeof(int); //表示式3
二、字串陣列長度的獲取
char str[] = {"This is a string!"};
length = sizeof(str)-1;//包含空格
之所結果要減1,是因為字串結束符'\0‘在陣列中佔用了一個位元組。三、原始碼
執行結果/************************************** *獲取字串長度(元素個數) By 羽墨 *print_length.c ***************************************/ #include <stdio.h> void main() { int array[] = {5,2,4,6,1,3}; char str[] = {"This is a string!"}; int length = sizeof(array)/sizeof(*array); printf("The length of string '%s' is %d\n",str,sizeof(str)-1); printf("The length of array is %d\n",length); }
The length of string 'This is a string!' is 17
The length of array is 6
四、注意1、如果在定義陣列時就給定了陣列的大小,如int array[len];,則不管陣列中初始化了多少個(顯然應不大於len)元素,最後的陣列中的元素個數都是len。所以要想獲得陣列中真實元素的個數,在初始化陣列時應注意這一點。
2、向子函式傳遞陣列後,然後在子函式內部獲取陣列長度。先來看一個錯誤示例程式:
int getLength(int array[])
{
int length;
length=sizeof(array)/sizeof(array[0]);
return length;
}
len = getLength(array);
printf("The length of array is %d\n",len);
這樣得到的結果始終都是1。因為陣列作為引數傳給函式時傳的是指標而不是陣列,傳遞的是陣列的首地址。在本示例中,函式名array傳遞到子函式後就完全退化為一個指標,該指標指向的是陣列array所在的地址,即陣列array第一個元素array[0]所在的地址。也就是說系統只是告訴該函式這個儲存空間存有資料,但並沒有告訴函式這個資料儲存空間有多大。sizeof(array)的結果是指標變數array所佔記憶體的位元組數,具體大小與系統有關,一般在32位機器上佔4個位元組,array[0]是int型別,同樣佔4個位元組,所以結果為1。所以要獲得陣列的長度最好在陣列定義所在的區域內。對於上述情形,查閱資料後給出兩種解決方案:
(1)進入子函式後用函式memcpy將陣列拷貝出來,函式memcpy所需要的長度由另一個形參傳遞進來,像這樣:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**************************************
*摘自360百科(稍作修改) By 羽墨
*將陣列內容拷貝到函式內部
***************************************/
void fun(char *p, int len)
{
char *pData;
pData = (char*) malloc (len+1); //申請記憶體空間
memcpy(pData, p, len+1); //拷貝陣列
printf("%s\n",pData);
//計算陣列大小(略)
free(pData); //釋放記憶體
pData = NULL;
}
void main ()
{
char str[] = {"This is a string!"};//初始化陣列
fun(str, 17);
}
個人覺得沒有必要怎麼做。如果能夠所需的長度作為形參傳遞到子函式中,顯然就不需要在子函式當中另行計算,so,請看另一個方案。(2)在子函式外部計算好元素個數後作為形參傳遞到子函式中進行其他操作。在這裡僅給出(直接)插入排序演算法的main函式,insert_sort(array,length)函式只需將子函式中用於記錄陣列元素個數的臨時變數length放進子函式的引數列表即可。
void main()
{
int array[] = {5,2,4,6,1,3};
char str[] = {"This is a string!"};
int length = sizeof(array)/sizeof(*array); //計算陣列中的元素個數
printf("The original");
print_array(array);
insert_sort(array,length); //插入排序
printf("The sorted");
print_array(array); //輸出排序結果
}
這樣一來,對於任意的目標序列都可以直接進行排序而不需要修改任何程式語句。