C语言常用库函数

Intro

最近发现一个问题,做题的时候,不管有的没的,要用的函数全靠自己写,写来写去也懒得去管到底有没有那个库函数了…这样不太好,日后还不是得把自己累死,还是得善于利用东西才行(又为自己偷懒找借口🤣)。于是,这篇文章就用来记录C中常用的一些库函数,以免日后又忘记了。

stdlib.h

stdlib.hstandard 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
6
int 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;
}

从上面的代码可以看出,指针ab在传入到compare比较函数内后,先进行了指针类型的强转操作,然后再分别对强转后的ab指针进行解引用,并做差来判断*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
#include <stdio.h>
#include <stdlib.h>

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
4
int 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);


Buy me a coffee ? :)
0%