目录
一、快速排序 qsort
1.介绍使用:
2:模拟实现:
二、字符串操作函数
1.strlen
(1)介绍使用
(2)模拟实现
2.strcmp
(1)介绍使用
(2)模拟实现
3.strcpy
(1)介绍使用
(2)模拟实现
4.strcat
(1)介绍使用
(2)模拟实现
5.strstr
三、内存操作函数
1.memcpy
(1)介绍使用
(2)模拟实现
2.memmove
(1)介绍使用
(2)模拟实现
一、快速排序 qsort
1.介绍使用:
我们先来看看这个函数的类型及使用方法:
该函数需要的头文件是<stdlib.h>或<search.h>,返回的类型是void;
简单介绍一下他的参数:
第一个:void *base 是一个voidl型的指针,所以我们在这里可以放任何类型的参数(int、char、float等),base 是首元素的地址;
第二个:size_t num 是要排序元素的个个数;
第三个:size_t width 是以字节为单位的数组元素大小;
第四个:int (__cdecl *compare )(const void *elem1, const void *elem2 ) 是比较两个元素大小返回的数值:前一个元素大于后一个元素返回1,等于则返回0,小于则返回-1(在不同编译器下返回值可能不一样,这里是VS编译器),如下:
举个例子吧,我们用整型数组举例:
int com_par(const void* e1, const void* e2)//void*指针可以接受任何类型的数据
{return *(int*)e1 - *(int*)e2;
}//比较两个整型大小,得出一个返回值int main()
{int arr[10] = { 1,3,6,8,7,9,5,2,4,0 };qsort(arr, 10, sizeof(arr[0]), com_par);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}//如果用浮点型数组,比较大小这一段代码部分只能如下:不然返回的类型为int则会将1.1-1.0得出值为0
int com_par2(const void* e1, const void* e2)//void*指针可以接受任何类型的数据
{if (*(float*)e1 - *(float*)e2>0){return 1;}if (*(float*)e1 - *(float*)e2 < 0)return -1;if (*(float*)e1 - *(float*)e2 == 0)return 0;
}
这里我们得出的是升序排序,如果要得到降序排序可以将比较大小函数那里返回值:return *(int*)e1 - *(int*)e2改为return *(int*)e2-*(int*)e1,就可以实现降序排序,结果如下:
2:模拟实现:
由上已经介绍过该函数的各个参数,所以就先直接上代码:
void my_qsort(void* base, int num, int width, int (*cmp)(const void* e1, const void* e2))
{int i = 0, j = 0;for (i = 0; i < num - 1; i++){for (j = 0; j < num - 1 - i; j++){if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}
不知道你是否察觉到我们的代码形式上是不是像冒泡排序的代码,没错,这就是根据冒泡排序的类型来实现的。
这里的cmp((char*)base + j * width, (char*)base + (j + 1) * width)中的width是指一个元素的字节大小,所以这里的j*width与(j+)*width所表示的就是前一个元素与后一个元素,就这样比较挨着的两个元素,判断返回值r如果>0(前者大于后者,升序排序,如果要降序排序就改为<0)就交换这
两个元素, 这里我们就编写一个Swap函数来进行交换:
void Swap(char* buf1, char* buf2, int width)
{int i = 0;for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}
然后在主函数调用:
int main()
{int arr[10] = { 1,3,2,5,4,6,8,7,9,0 };my_qsort(arr, 10, sizeof(arr[0]), cmp_int);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}
}
int cmp_int(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}
得出结果为:
二、字符串操作函数
头文件为<string>
1.strlen
(1)介绍使用
strlen,返回的是一个数值,使用时的参数为char*类型的数组名(即字符串首的地址);使用如下:
#include<string.h>
#include <stdio.h>
int main()
{char arr[20] = "abcdefghijk";int len = strlen(arr);printf("len=%d\n", len);return 0;
}
注意:只能实现字符串计数。
(2)模拟实现
先上代码:
int my_strlen(const char* arr)
{int n = 0;while (*arr++ != '\0'){n++;//只要arr不等于‘\0’,循环一次n就加1}return n;
}
只要从首元素开始接着往后走n+1,当*arr为‘\0’时,即arr这个数组中的元素个数统计完得到n,最后返回数值n;运行如下:
2.strcmp
(1)介绍使用
比较两个字符的大小,用ASCALL码比较。
它的两个参数都是char*类型,返回的类型为int型,如下:
举个例子来说明吧:
int main()
{char arr1[10] = "c";char arr2[10] = "h";int et = strcmp(arr1, arr2);printf(" %d", et);return 0;
}
返回值为-1,说明c<h。
注: 这里进行比较的是字符对应的ASCALL码。
(2)模拟实现
代码如下:
int str_cmp(char* arr1, char* arr2)//参数为两个char*
{while (*arr1 == *arr2){//如果比较的两个字符相同且当某一个为“\0”时,就返回0if (*arr1 == '\0')return 0;arr1++;arr2++;}
//如果比较时两个不同if (*arr1 > *arr2)return 1;//arr1字符大于arr2返回1else if (*arr1 < *arr2)return -1;//arr1小于arr2返回-1
}
然后在主函数进行调用:
int main()
{char arr1[10] = "c";char arr2[10] = "h";int et = strcmp(arr1, arr2);//库函数int ret = str_cmp(arr1, arr2);//自己写的printf(" %d %d", ret,et);//判断我们写的与库函数的结果是否一样return 0;
}
很明显答案是一样的,所以我们写的没有错。
3.strcpy
(1)介绍使用
拷贝字符串在另外一个数组里面,会覆盖原内容。
两个参数是char*,第一个参数是我们要 拷进的地址,第二个是被拷贝地址,也就是拷贝strSource的内容到strDestination。前提是strDestination的空间要大于等于strSource的空间。
举例:
int main()
{char arr1[10] = "abcdefg";char arr2[10] = "asdf";printf("原arr2=%s\n", arr2);strcpy(arr2, arr1);printf("新arr2=%s", arr2);return 0;
}
(2)模拟实现
void str_cpy(char* arr1, char* arr2)
{while (*arr1 = *arr2)//这里是直接将arr2赋给arr1,前提是arr2!=‘\0’{//依次向后移动arr1++;arr2++;}
}
int main()
{char arr1[10] = "asdfgf";char arr2[10] = "bfdce";str_cpy(arr1, arr2);printf("%s", arr1);return 0;
}//当然这里还可以在简便一点,运行结果一样
void str_cpy(char* arr1, char* arr2)
{while (*arr1++ = *arr2++){;}
}
结果如下:
4.strcat
(1)介绍使用
将strSource的内容连接到strDestination后面,要求前者有足够的空间容纳后者拷贝进来。
如:
int main()
{char arr1[20] = "abcd";char arr2[10] = "efghijk";strcat(arr1, arr2);printf("%s", arr1);return 0;
}
(2)模拟实现
char* str_cat(char* arr1, char* arr2)
{while (*arr1)//先让arr1移动到‘\0’处{arr1++;}while (*arr1++ = *arr2++)//从‘\0’处开始拷贝arr2的内容{;}
}int main()
{char arr1[10] = "abc";char arr2[5] = "def";str_cat(arr1, arr2);printf("%s", arr1);return 0;
}
5.strstr
(1)介绍使用
从string中查找有没有strCharSet中一样的字符串,有就返回string中这段字符串与后面的字符,如果没有就返回一个空指针(NULL);如下:
int main()
{char arr1[20] = "abcdebcdefgh";char arr2[10] = "bcdef";char *ret=strstr(arr1, arr2);printf("%s", ret);
}
(2)模拟实现
char* str_str(char* arr1, char* arr2)
{char* s1 = arr1;//接受接受cur中的字符,与arr1进行判断是否相等char* s2 = arr2;//接受arr2中的每一个字符char* cur = arr1;//接受arr1中的每一个字符while (*cur){s1 = cur;s2 = arr2;while (*s1 && *s2 && *s1 == *s2){//s1与s2都不为‘\0'且s1与s2要相等,就往后面一直查找,当遇到‘\0’就停止s1++;s2++;}if (*s2 == '\0')//如果是s2为‘\0’,说明在s1中有与s2相等的字符串,就从这里返回curreturn cur;cur++;//如果s1与s2判断有不相等,然后cur就往后移动一个字符,再进行判断}return NULL;//如果判断完,s1中没有s2的字符串就返回一个空指针
}
int main()
{char arr1[10] = "abcbebcd";char arr2[5] = "bcd";char* ret = str_str(arr1, arr2);printf("%s", ret);return 0;
}
三、内存操作函数
头文件<string.h>
1.memcpy
(1)介绍使用
将src以count个字节大小拷贝到dest中。如下:
int main()
{int a[10] = { 1,2,3,4,5,6,7,8,9 ,10 };int a1[5] = { 0 };int i = 0;memcpy(a1, a, 20);for (i = 0; i < 5; i++){printf("%d ", a1[i]);}
}
注意:count是字节单位的大小,而不是个数。
(2)模拟实现
void* my_memcpy(void* dest, const void* str, size_t count)
{void* ret = dest;//用于返回while (count--){*(char*)dest = *(char*)str;//赋值dest = (char*)dest + 1;//因为dest是void型所以先转换为char*类型加1后赋给dest,下同str = (char*)str + 1;}return ret;
}
int main()
{int a[10] = { 1,2,3,4,5,6,7,8,9 ,10 };int a2[5] = { 0 };my_memcpy(a2, a, 20);int i = 0;for (i = 0; i < 5; i++)printf("%d ", a2[i]);return 0;
}
但是我们这样写有一个缺点(有的编译器下使用memcpy函数也是这样):
int main()
{int a[10] = { 1,2,3,4,5,6,7,8,9 ,10 };int a2[5] = { 0 };my_memcpy(a+2, a, 20);int i = 0;for (i = 0; i < sizeof(a)/sizeof(a[0]); i++)printf("%d ", a[i]);return 0;
}
如果是这样,输出的结果本应该为1 2 1 2 3 4 5 8 9 10,但实际输出结果为:
所以这就略有区别,但是用memmove就不会这样,。
2.memmove
(1)介绍使用
类型与用法与memcpy相似。
int main()
{int a[10] = { 1,2,3,4,5,6,7,8,9 ,10 };int i = 0;memmove(a + 2, a, 20);for (i = 0; i < sizeof(a) / sizeof(a[0]); i++){printf("%d ", a[i]);}return 0;
}
(2)模拟实现
如图,我们要考虑当dest的空间在这个位置时,我们要拷贝src数据(3 4 5 6 7)时,只能从1->5方向这么去拷贝,如果从5->1拷贝就会将前面的3 4 5被覆盖,就会拷贝错误.。
如果当dest的空间为(6 7 8 9 10)时,拷贝src数据就只能从后往前拷贝(10->6),如果从6->10就会覆盖掉6 7。
所以拷贝时当dest在src前面时就从前往后拷贝,当dest在src后面时就从后往前拷贝。
void* my_memmove(void* dest, const void* str, size_t count)
{void* ret = dest;//作为返回值if (dest < str)//从前往后拷{while (count--){*(char*)dest = *(char*)str;dest = (char*)dest + 1;str = (char*)str + 1;}}//从后往前拷elsewhile (count--){*((char*)dest + count) = *((char*)str + count);}return ret;
}
int main()
{int a[10] = { 1,2,3,4,5,6,7,8,9 ,10 };int i = 0;my_memmove(a + 2, a, 20);for (i = 0; i < sizeof(a) / sizeof(a[0]); i++){printf("%d ", a[i]);}return 0;
}
感谢阅读;多多指教