由於C語言是強型別語言,所以通常我們在編寫一些函式的時候就需要指定函式的型別。這就會導致同樣的函式行為因為處理的型別不同,就可能需要為不同的型別編寫不同的函式版本。
比如用於交換兩個變數值的如swap
函式:
void swap(int *v1, int *v2) {
int *temp = v1;
*v1 = *v2;
*v2 = *temp;
}
上面的swap
函式只能交換兩個int
型別的整數。
如果需要交換兩個double
型別的浮點數就需要再寫一個double
型別版本的swap
函式:
void swap(double *v1, double *v2) {
int *temp = v1;
*v1 = *v2;
*v2 = *temp;
}
所謂
泛型swap函式
就是一個swap函式就能夠處理不同型別的交換工作。在C++有模版
來實現泛型,但是C語言中沒有模板
,所以我們可以使用void
型別的指標來實現泛型swap函式
,任何型別的指標都可以賦值給void
型別的指標。
泛型swap函式
實現:
void swap(void *v1, void *v2, size_t size) {
void *temp = malloc(size);
assert(temp != NULL);
memcpy(temp, v1, size);
memcpy(v1, v2, size);
memcpy(v2, temp, size);
free(temp);
}
先對函式中出現的3個函式分別加以說明:
- malloc
函式原型為void *malloc(size_t __size)
。該函式用來向堆中動態申請一塊記憶體。它會向堆中動態申請引數__size
個位元組大小的記憶體空間,如果申請成功就返回申請到的空間首地址,申請失敗就返回NULL
。
- memcpy
函式原型為void *memcpy(void *dest, const void *src, size_t n)
。該函式用來實現記憶體拷貝,它把引數src
所指向的記憶體空間拷貝n
個位元組到引數dest
所指向的記憶體空間中。
- free
函式原型為void free(void *ptr)
,該函式用來釋放動態申請的記憶體。它把引數ptr
所指向的動態申請的記憶體空間進行釋放。
函式簽名void swap(void *v1, void *v2, size_t size)
中的前兩個引數使用了void
型別的指標,第三個引數size
表示需要交換的型別在記憶體中所佔位元組數量。
第2~3行程式碼是向堆中
申請size
個位元組大小的空間,然後將空間首地址賦值給temp
指標,並斷言記憶體是否申請成功。
第4~6行程式碼是通過記憶體拷貝
的方式來實現交換步驟。
第7行程式碼是把在第3行程式碼中動態申請到的size
個位元組大小的記憶體空間進行釋放,以免發生記憶體洩漏。
對swap
函式進行呼叫,交換兩個int
型別變數的值:
int main() {
int a = 123;
int b = 321;
printf("before swap: %d, %d\n", a, b);
swap(&a, &b, sizeof(int));
printf("after swap: %d, %d\n", a, b);
return 0;
}
輸出:
before swap: 123, 321
after swap: 321, 123
對swap
函式進行呼叫,交換兩個double
型別變數的值:
int main() {
double a = 123;
double b = 321;
printf("before swap: %f, %f\n", a, b);
swap(&a, &b, sizeof(double));
printf("after swap: %f, %f\n", a, b);
return 0;
}
輸出:
before swap: 123.000000, 321.000000
after swap: 321.000000, 123.000000
執行實現中的完整程式碼還需要引入標頭檔案:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
以上就是泛型swap
函式的具體實現,主要是運用了void
指標和記憶體拷貝
。可以借鑑實現思路來研究關於C語言實現泛型的更多例子。
本作品採用《CC 協議》,轉載必須註明作者和本文連結