Intro
最近发现一个问题,做题的时候,不管有的没的,要用的函数全靠自己写,写来写去也懒得去管到底有没有那个库函数了…这样不太好,日后还不是得把自己累死,还是得善于利用东西才行(又为自己偷懒找借口🤣)。于是,这篇文章就用来记录C
中常用的一些库函数,以免日后又忘记了。
stdlib.h
stdlib.h
即standard library
标准库头文件,这个头文件内有很多有用的工具函数。
qsort
qsort
函数是C
语言自带的排序函数,采用排序方法是快速排序,其声明位于头文件stdlib.h
中,貌似快速排序是实际使用效果最好的几种排序方法之一。
Function Prototype
函数原型如下:1
void qsort(void *base, size_t num, size_t size, int (*compare)(const void *, const void *));
参数说明:
base
指向数组的起始地址,通常会传入一个数组名
num
表示该数组元素的个数
size
表示数组中每个元素的大小(字节数)
(*compare)(const void*, const void*)
为指向比较函数的函数指针,决定了排序顺序
Compare Function
qsort
函数声明中的compare
参数是一个指针,指向一个比较两个元素的函数。比较函数的原型应该是int compare(const void *a, const void *b);
,注意这个函数的形参是const void *
型,也就是说,是不限制参数指针类型的,并且,返回值是int
型的。qsort
函数在使用compare
函数指针调用compare
比较函数时,传入的实参是没有限定指针类型的。一般而言,compare
函数按照下面的代码来写:1
2
3
4
5
6int compare(const void *a, const void *b)
{
if(*(int*)a < *(int*)b) return -1;
if(*(int*)a == *(int*)b) return 0;
if(*(int*)a > *(int*)b) return 1;
}
从上面的代码可以看出,指针a
和b
在传入到compare
比较函数内后,先进行了指针类型的强转操作,然后再分别对强转后的a
和b
指针进行解引用,并做差来判断*a
和*b
的大小,根据三种不同的情况返回三个值,分别对应以下三种情况:
(*a)
所指向元素会被排在*(b)
所指向元素之前
(*a)
所指向元素和*(b)
所指向元素之间顺序不确定
(*a)
所指向元素会被排在*(b)
所指向元素之后
Examples
对普通int
型数组进行排序时:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int compare(const void *a, const void *b)
{
return (*(int*)a - *(int*)b);
}
int main(int argc, char const *argv[])
{
int i, array[8] = {30, 52, 11, 29, 58, 3, 88, 60};
qsort(array, 8, sizeof(array[0]), compare);
for(i=0; i<8; i++)
{
printf("%d ", array[i]);
}
return 0;
}
/*
Print: 3 11 29 30 52 58 60 88
if '(*(int*)b - *(int*)a)' replaces '(*(int*)a - *(int*)b)'
then Print: 88 60 58 52 30 29 11 3
*/
对其他类型的数组而言,使用方法也大致如此,对字符串数组(即二维字符数组)使用时,可以将比较函数这样写:1
2
3
4int compare(const void *a, const void *b)
{
return (strcmp((char*)a, (char*)b));
}
配合strcmp
函数使用就会很方便。
另外,快速排序
是不稳定的排序算法,对于结构体而言,当两个元素的值相等时,经过快速排序后,其相对位置可能发生了改变,这就导致结构体排序完成之后,输出结果不对(但是序列有序无误),为了避免这种情况,需要在结构体内新增一个标记位
,当两个结构体值相等时,比较标志位的大小,从而保持二者相对位置不发生改变。
ctype.h
ctype.h
这个头文件全称应该是character type
吧,因为其内部定义了一批 C 语言字符分类函数,用于测试字符是否属于特定的字符类别。这些函数实现起来都不难,再重复造轮子就有点划不来了。
在 C 语言中,对于一个字符变量而言,其本质依然是整型变量,所以下面函数形参类型就直接用int
了。换句话来讲,这些函数的实现原理应该就是直接与 ASCII 码进行比较。
isalpha
这个函数用于判断传入的字符是否是字母(包含大小写)。
函数原型:1
int isalpha(int ch);
若传入的字符是字母,则返回非零,若不是则返回0。
isdigit
这个函数用于判断传入的字符是否是罗马数字(0-9)。
函数原型:1
int isdigit(int ch);
若传入的字符是数字,则返回非零,若不是则返回0。
isxdigit
这个函数用于判断传入的字符是否是十六进制字符(0-9、A-Z、a-z)。
函数原型:1
int isxdigit(int ch);
若传入的字符是十六进制字符,则返回非零,若不是则返回0。
islower
这个函数用于判断传入的字符是否是小写字母(a-z)。
函数原型:1
int islower(int ch);
若传入的字符是小写字母,则返回非零,若不是则返回0。
isupper
这个函数用于判断传入的字符是否是大写字母(A-Z)。
函数原型:1
int isupper(int ch);
若传入的字符是大写字母,则返回非零,若不是则返回0。
tolower
这个函数用于将传入的字符转换为小写字母。
函数原型:1
int tolower(int ch);
返回值为所传入字符变量的小写字母。
toupper
这个函数用于将传入的字符转换为大写字母。
函数原型:1
int tolower(int ch);
返回值为所传入字符变量的大写字母。
isalnum
这个函数用于判断传入的字符是否是字母或数字。
函数原型:1
int isalnum(int ch);
若传入的字符是字母或数字,则返回非零,若不是则返回0。
string.h
strcpy
这个函数用于拷贝字符串。
函数原型:1
char *strcpy(char *dest, char *src);
需要注意的是 dest 数组必须要足够大,不然可能会造成缓冲溢出的情况。
math.h
ceil
返回不小于 x 的最小整数(向上取整),函数原型:1
double ceil(double x);
floor
返回不大于 x 的最大整数(向下取整),函数原型:1
double floor(double x);
round
返回 x 的四舍五入整数值,函数原型:1
double round(double x);