Look at the following function swap, which swaps the contents of two elements, using the integer int as an example:
void swap(int* i1,int* i2){
int temp;
temp = *i1;
*i1 = *i2;
*i2 = temp;
}
When you want to swap two char types, you still have to rewrite a function with parameter type char. Can we use a void pointer as a parameter? See the following changes:
void swap(void *vp1,void *vp2){
void temp = *vp1;
*vp1 = *vp2;
*vp2 = temp;
}
This code is wrong and will not compile. First, variables cannot be declared asvoidvoid. And you don't know what type the parameter passed to this function is, so you cannot determine a type declaration. At the same time, you cannot apply*it to a void pointer, because the system has no information about the size of the object pointed to by this address. At compile time, the compiler cannot know the type of the parameter passed to this function. To implement a generic function here, you need to pass in the address space size size of the objects to be swapped at the call site, and use the memcpy() function defined in the header file string.h. The changes are as follows:
void swap(void *vp1,void *vp2,int size){
char buffer[size];//注意此处gcc编译器是允许这样声明的
memcpy(buffer,vp1,size);
memcpy(vp1,vp2,size);
memcpy(vp2,buffer,size);
}
When calling this function, you can call it as follows (it also applies to other types of x, y):
int x = 27,y = 2; swap(&x,&y,sizeof(int));
Next, let's look at a function with another functionality:
int lsearch(int key,int array[],int size){
for(int i = 0;i < size; ++i)
if(array[i] == key)
return i;
return -1;
}
This function searches for the key element in the array array. If found, it returns its index; otherwise, it returns -1.
As above, generic functions can also be implemented:
void* lsearch(void* key, void *base, int n, int elemSize){
for(int i = 0;i < n; ++i){
void *elemAddr = (char *)base+i*elemSize;
if(memcmp(key, elemAddr, elemSize) == 0)
return elemAddr;
}
return NULL;
}
Line 3 of the code: casting the first address of the array to a pointer to char type uses the feature that char type is 1 byte in size, so that elemAddr points to the first address of the i-1th element of this "generic" array. As mentioned before, at this time you don't know what type of data you passed in, and the system cannot determine how long one element of this array is or how many bytes are needed to skip to the next element. Therefore, by casting to a pointer to char and adding the product of the element size information passed in and the accumulated count i, i.e., the offset address, you can get the first address of the i-1th element of this array. In this way, no matter what type of pointer the passed parameter points to, you can get a pointer to the correct element, thereby implementing generic programming.
Function memcmp() prototype: int memcmp(void *dest, const void *src, int n), compares the contents of two memory areas of length n whose first addresses are dest and src respectively.
This function searches for the key element in the array base. If found, it returns its address information; otherwise, it returns NULL.
If function pointers are used, the genericity of its behavior can be achieved:
void *lsearch(void *key,void *base,int n,int elemSize,int(*cmpfn)(void*,void*,int)){
for(int i = 0;i < n; ++i){
void *elemAddr = (char *)base+i*elemSize;
if(cmpfn(key,elemAddr,elemSize) == 0)
return elemAddr;
}
return NULL;
}
Then define a function to be called:
int intCmp(void* elem1,void* elem2){
int* ip1 = elem1;
int* ip2 = elem2;
return *ip1-*ip2;
}
Look at the following call:
int array[] = {1,2,3,4,5,6};
int size = 6;
int number = 3;
int *found = lsearch(&number,array,size,sizeof(int),intCmp);
if(found == NULL)
printf("NO\n");
else
printf("YES\n");
C can also implement a certain degree of generic programming, but it is unsafe and the system only performs limited checks on it. You must be extra careful when programming.
Original URL: https://www.cnblogs.com/wuyudong/p/c-general-function1.html