首頁 > 軟體

C語言可變引數與記憶體管理超詳細講解

2023-01-04 14:00:13

概述

有時,您可能會碰到這樣的情況,您希望函數帶有可變數量的引數,而不是預定義數量的引數。C 語言為這種情況提供了一個解決方案,它允許您定義一個函數,能根據具體的需求接受可變數量的引數。下面的範例演示了這種函數的定義。

int func(int, ... ) 
{
   .
   .
   .
}
int main()
{
   func(2, 2, 3);
   func(3, 2, 3, 4);
}

請注意,函數func()最後一個引數寫成省略號,即三個點號(...),省略號之前的那個引數是int,代表了要傳遞的可變引數的總數。為了使用這個功能,您需要使用stdarg.h標頭檔案,該檔案提供了實現可變引數功能的函數和宏。具體步驟如下:

  • 定義一個函數,最後一個引數為省略號,省略號前面可以設定自定義引數。
  • 在函數定義中建立一個va_list型別變數,該型別是在 stdarg.h 標頭檔案中定義的。
  • 使用int引數和va_start宏來初始化va_list變數為一個參數列。宏 va_start 是在 stdarg.h 標頭檔案中定義的。
  • 使用va_arg宏和va_list變數來存取參數列中的每個項。
  • 使用宏va_end來清理賦予va_list變數的記憶體。

現在讓我們按照上面的步驟,來編寫一個帶有可變數量引數的函數,並返回它們的平均值:

#include <stdio.h>
#include <stdarg.h>
double average(int num,...)
{
    va_list valist;
    double sum = 0.0;
    int i;
    /* 為 num 個引數初始化 valist */
    va_start(valist, num);
    /* 存取所有賦給 valist 的引數 */
    for (i = 0; i < num; i++)
    {
       sum += va_arg(valist, int);
    }
    /* 清理為 valist 保留的記憶體 */
    va_end(valist);
    return sum/num;
}
int main()
{
   printf("Average of 2, 3, 4, 5 = %fn", average(4, 2,3,4,5));
   printf("Average of 5, 10, 15 = %fn", average(3, 5,10,15));
}

當上面的程式碼被編譯和執行時,它會產生下列結果。應該指出的是,函數average()被呼叫兩次,每次第一個引數都是表示被傳的可變引數的總數。省略號被用來傳遞可變數量的引數。

Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000

C 語言為記憶體的分配和管理提供了幾個函數。這些函數可以在<stdlib.h>標頭檔案中找到。

注意:void * 型別表示未確定型別的指標。C、C++ 規定 void * 型別可以通過型別轉換強制轉換為任何其它型別的指標。

動態分配記憶體

程式設計時,如果您預先知道陣列的大小,那麼定義陣列時就比較容易。例如,一個儲存人名的陣列,它最多容納 100 個字元,所以您可以定義陣列,如下所示:

char name[100];

但是,如果您預先不知道需要儲存的文字長度,例如您想儲存有關一個主題的詳細描述。在這裡,我們需要定義一個指標,該指標指向未定義所需記憶體大小的字元,後續再根據需求來分配記憶體,如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
   char name[100];
   char *description;
   strcpy(name, "Zara Ali");
   /* 動態分配記憶體 */
   description = (char *)malloc( 200 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memoryn");
   }
   else
   {
      strcpy( description, "Zara ali a DPS student in class 10th");
   }
   printf("Name = %sn", name );
   printf("Description: %sn", description );
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Name = Zara Ali
Description: Zara ali a DPS student in class 10th

上面的程式也可以使用calloc()來編寫,只需要把 malloc 替換為 calloc 即可,如下所示:

calloc(200, sizeof(char));

當動態分配記憶體時,您有完全控制權,可以傳遞任何大小的值。而那些預先定義了大小的陣列,一旦定義則無法改變大小。

重新調整記憶體的大小和釋放記憶體

當程式退出時,作業系統會自動釋放所有分配給程式的記憶體,但是,建議您在不需要記憶體時,都應該呼叫函數free()來釋放記憶體。

或者,您可以通過呼叫函數realloc()來增加或減少已分配的記憶體塊的大小。讓我們使用 realloc() 和 free() 函數,再次檢視上面的範例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
   char name[100];
   char *description;
   strcpy(name, "Zara Ali");
   /* 動態分配記憶體 */
   description = (char *)malloc( 30 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memoryn");
   }
   else
   {
      strcpy( description, "Zara ali a DPS student.");
   }
   /* 假設您想要儲存更大的描述資訊 */
   description = (char *) realloc( description, 100 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memoryn");
   }
   else
   {
      strcat( description, "She is in class 10th");
   }
   printf("Name = %sn", name );
   printf("Description: %sn", description );
   /* 使用 free() 函數釋放記憶體 */
   free(description);
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Name = Zara Ali
Description: Zara ali a DPS student.She is in class 10th

您可以嘗試一下不重新分配額外的記憶體,strcat() 函數會生成一個錯誤,因為儲存 description 時可用的記憶體不足。

到此這篇關於C語言可變引數與記憶體管理超詳細講解的文章就介紹到這了,更多相關C語言可變引數 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com