若是在做用域內,變量以數組形式聲明,則可使用sizeof求數組大小,下面一段代碼展現瞭如何使用sizeof:c++
int nums[] = {11,22,33,44,55,66}; int i; // sizeof(nums) 計算nums數組的總字節數 // sizeof(int) 計算int類型所佔用的字節數 int length = sizeof(nums)/sizeof(int); for(i=0;i<length;i++) { printf("%d ",nums[i]); }
其中sizeof(nums)表明計算nums數組的總字節數,而sizeof(int)則表明計算int類型所佔用的字節數(32位系統下是4個字節,64位下可能不一樣,所以這裏使用sizeof(int)能夠向程序員屏蔽這個差別),運行結果爲:程序員
假如咱們將上面的代碼作一個抽象,將數組的遍歷及打印封裝爲一個方法,代碼以下:數組
void printEach(int* nums) { // sizeof(nums)在這裏是計算指針的字節數 int length = sizeof(nums)/sizeof(int); printf("The length of nums is %d\n",length); int i; for(i=0;i<length;i++) { printf("%d ",nums[i]); } }
咱們定義了一個printEach方法,其參數是一個指針,在方法內部經過sizeof計算數組長度。可是,運行結果並無同上面的結果一致:安全
咱們發現,雖然咱們使用了指針,但因爲sizeof是編譯器在編譯的時候計算的,沒法動態計算。所以對於int *或者將數組傳遞給函數,那麼就沒法使用sizeof獲取大小了。即便函數聲明中寫着int[]也不行(爲了不誤解,不要在參數中聲明數組類型)。這裏,sizeof(nums)只是計算了指針的字節數(這裏指針指向了數組的首元素的地址,一個int佔4個字節,因此最後length變成了1)。函數
那麼,爲了不出現沒法計算長度的狀況,咱們通常都會在方法定義時增長一個長度的參數,讓調用者傳遞過來,函數內部再也不計算長度。看看以下的代碼:spa
void printEachWithLen(int* nums,int length) { int i; for(i=0;i<length;i++) { printf("%d ",nums[i]); } }
這時候,咱們就能夠在main函數中調用該printEachWithLen()函數:3d
int length = sizeof(nums)/sizeof(int); printEachWithLen(nums,length);
這下看看結果:指針
所以,通常給函數傳遞數組/字符串的時候都要求額外傳遞「長度」參數,由於函數內部也不知道「有多長」。例如:memcpy(void * restrict, const void * restrict, size_t),第三個參數size_t就是長度。又例如在.NET中,要進行數組的複製,可使用 Array.Copy 、Buffer.BlockCopy 、Array.ConstrainedCopy等方法,經過查看其方法定義,都要求傳遞了數組長度。rest
const int INT_SIZE = 4; int[] arr = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; Buffer.BlockCopy(arr, 3 * INT_SIZE, arr, 0 * INT_SIZE, 4 * INT_SIZE); foreach (int value in arr) Console.Write("{0} ", value); // The example displays the following output: // 8 10 12 14 10 12 14 16 18 20
一個簡單的場景,將一個字符串複製到另外一個字符串中,在C語言課本中,最長出現的就是strcpy了。咱們能夠輕易地寫出下面的代碼來實現字符串複製:code
char sourceStr[] = "hello edison"; char destStr[30]; strcpy(destStr,sourceStr); printf("%s",destStr);
運行結果以下圖所示:
可是,咱們經常聽人說strcpy是不安全的函數,爲何呢?先看看strcpy內部的循環判斷條件:
while ((*strDest++ = *strSrc++) != '\0')
這個循環會一直執行,直到循環條件爲空,即'\0',也就是說,若是strDest所指的存儲空間不夠大的話,這個函數會將strSrc中的部份內容拷貝到strDest所指內存空間後面的內存中。而strDest所指空間後面的內存倒是不可知的,有可能已經被其餘資源佔用了,這樣就會破壞原先存儲的內容,致使系統崩潰。
由於strcpy在執行字符串拷貝的時候,會從strSrc所指位置開始,檢測當前內存單元中存儲的數據是否爲'\0'。若是不爲'\0',則將這個內存單元中的數據拷貝到strDest所指向的內存中。若是strSrc中存儲的字符串長度大於dst所申請的內存空間的話,就會產生越界,形成不可預知的後果。
PS:strlen根據'\0'判斷字符串結束,那麼惡意攻擊者能夠構造一個不包含'\0'的字符串,而後讓數據寫入數組以外的程序內存空間,從而進行破壞。
(1)strncpy函數定義:
char *strncpy(char *dest, const char *src,int count)
將字符串src中的count個字符拷貝到字符串dest中去,最後返回指向dest的指針。
(2)strncpy用法解析:
這個函數和strcpy相似,當src的長度大於dst申請的空間的時候,狀況和strcpy同樣;
若是第3個參數count的值大於src中字符串的長度的話,就會將字符串src拷貝到dst中,返回函數。
注意:若是源串長度大於n,則strncpy不復制最後的'\0'結束符,因此是不安全的,複製完後須要手動添加字符串的結束符才行。
char sourceStr[] = "hello edison"; char destStr[30]; int len = sizeof(sourceStr)/sizeof(char); printf("%d\n",len); strncpy(destStr,sourceStr,len-1); // 保證安全的字符串複製 destStr[len-1]='\0'; printf("%s",destStr);
運行結果以下圖所示:
如鵬網,《C語言也能幹大事(第三版)》