23 库对数值和字符数据的支持

23.1 float.h:浮点型的特性

说明:提供了用来定义浮点型的范围和精度的宏(没有类型和函数的定义)。
应用:由于只有进行数值分析的专家才会对上述float.h中定义的宏感兴趣,这可能是标砖哭中最不常用的宏。

23.1.1 对浮点数通用的宏

FLT_ROUND宏

说明:浮点加法的舍入模式,存在5中可能
Alt text

FLT_RADIX宏

说明:指定了基数的形式,最小值是2(二进制)

23.1.2 其它宏

说明:其他宏用来描述特定类型的特性。
宏命名:根据宏是针对的浮点类型有不同的前缀

宏前缀 针对的浮点类型
FLT float
DBL double
LDBL long double

与有效数字个数相关的宏

Alt text

与指数相关的宏

Alt text

其它宏

说明:描述了最大值、最接近0的值(最小正数),两个数之间的最小差值。
Alt text

23.2 limit.h:整值类型的大小

说明:提供了用于定义每种整型和字符型取值范围的宏(没有类型或函数)。

23.2.1 用于字符型的宏

说明:char、signed char、unsigned char
注意:char类型在有些机器上默认为unsigned char,有些默认为signed char。CHAR_MIN和CHAR_MAX的值因不同情况有所不同。

字符类型 CHAR_MIN
signed char SCHAR_MIN
unsigned char 0

字符类型 CHAR_MAX
signed char SCHAR_MAX
unsigned char UCHAR_MAX

Alt text

23.2.2 用于整型的宏

说明:[{signed|unsigned}] [{short|long}] int
用途:在查看编译器是否支持特定大小的整数时十分方便
Alt text

1
2
3
4
// 使用预处理指令判断int型是否可以用来存储100 000
#if INT_MAX < 100000
#error int type is too small// 终止编译
#endif
1
2
3
4
5
6
// 选择正确的类型定义
#if INT_MAX >= 100000
typedef int Quantity;
#else
typedef long int Quantity;
#endif

23.3 math.h:数学计算

说明:包含5中类型

  1. 三角函数
  2. 双曲函数
  3. 指数和对数函数
  4. 幂函数
  5. 就近取整函数绝对值函数和取余函数

23.3.1 错误

相关库:errno.h
特点:math.h中,大多数函数会将一个错误代码存储到一个名字为errnomath.h)的特定变量中(这一点不同于其他库)。
相关宏:HUGE_VAL(math.h, IEEE标准)

说明:math.h中定义,double类型,不一定是一个普通的数,代表无穷大(7.2)。
用途:当函数的返回值大于double类型的最大值时,会返回HUGE_VAL

更多错误:附录D

参数超出定义域

描述:函数的是惨超出了函数的定义域。
会被存储到errno中的宏:EDOM(定义域错误)
返回值:NAN(math.h, IEEE标准)

返回值超出取值范围

描述:函数的返回值超出了double类型的取值范围。
会被存储到errno中的宏:ERANGE(取值范围错误),绝对值过小(下溢出)的情况又可能不存储ERANGE
返回值:分两种情况

  1. 绝对值过大:根据返回值的正负返回正或负的HIGE_VAL
  2. 绝对值过小:返回0

23.3.2 三角函数

cos函数

说明:余弦
原型:math.h

1
2
3
4
5
/**
* @param {double} x 弧度
* @return {double} 余弦值
*/

double cos(double x);

sin函数

说明:正弦
原型:math.h

1
2
3
4
5
/**
* @param {double} x 弧度
* @return {double} 正弦值
*/

double sin(double x);

tan函数

说明:正切
原型:math.h

1
2
3
4
5
/**
* @param {double} x 弧度
* @return {double} 正切值
*/

double tan(double x);

acos函数

说明:反余弦
原型:math.h

1
2
3
4
5
/**
* @param {double} x 余弦值
* @return {double} 余弦值对应的弧度(0~π)
*/

double acos(double x);

asin函数

说明:反正弦
原型:math.h

1
2
3
4
5
/**
* @param {double} x 正弦值
* @return {double} 正弦值对应的弧度(-π/2~π/2)
*/

double asin(double x);

atan函数

说明:反正切
原型:math.h

1
2
3
4
5
/**
* @param {double} x 正切值
* @return {double} 正切值对应的弧度(-π/2~π/2)
*/

double atan(double x);

atan2函数

说明:反正切,atan(x)<==>atan2(x, 1.0)
原型:math.h

1
2
3
4
5
6
/**
* @param {double} y y
* @param {double} x x
* @return {double} 正切值对应的弧度(-π~π)
*/

double atan2(double x, double y);
1
2
3
4
5
6
7
cos(PI/4);// 0.707107
sin(PI/4);// 0.707107
tan(PI/4);// 1.0

acos(1.0);// 0.0
asin(1.0);// 1.5708
atan(1.0);// 0.785398

23.3.4 双曲函数

cosh函数

说明:计算双曲余弦
原型:math.h

1
2
3
4
5
/**
* @param {double} x 弧度
* @return {double} 双曲余弦值
*/

double cosh(double x);

sinh函数

说明:计算双曲正弦
原型:math.h

1
2
3
4
5
/**
* @param {double} x 弧度
* @return {double} 双曲正弦值
*/

double sinh(double x);

tanh函数

说明:计算双曲正切
原型:math.h

1
2
3
4
5
/**
* @param {double} x 弧度
* @return {double} 双曲正切值
*/

double tanh(double x);
1
2
3
cosh(0.5);// 1.12763
sinh(0.5);// 0.521095
tanh(0.5);// 0.462117

22.3.4 指数函数和对数函数

exp函数

说明:返回e的幂
原型:math.h

1
2
3
4
5
/**
* @param {double} x 指数
* @return {double} e的x次幂
*/

double exp(double x);
1
2
// e的3次幂
exp(3.0);// 20.0855

log函数

说明:以e为底的对数(exp函数的逆运算)
原型:math.h``

1
2
3
4
5
/**
* @param {double} x 真数
* @return double 以e为底x的对数
*/

double log(double x);
1
log(20.0855);// 3.0

log10函数

说明:计算常用对数(以10为底的对数)
原型:math.h

1
2
3
4
5
/**
* @param {double} x 真数
* @return {double} 以10为底x的对数
*/

double log10(double x);
1
log10(1000);// 3.0
1
2
3
4
5
6
7
8
9
/**
* 对任意的x和b,计算以b为底x的对数
* @param {double} x 真数
* @param {double} b 底数
* @return {double} 以b为底x的对数
*/

double logb(double x. double b) {
return log(x) / log(b);
}

frexp函数

说明:将浮点数拆成小数部分f和指数部分n,使得原始值等于f x 2^n
用途:主要供math.h中的其他函数点用,很少在程序中直接使用
原型:math.h

1
2
3
4
5
6
/**
* @param {double} value 浮点数原始值
* @param {double *} iptr 存储n的地址
* @return {double} f(0.5<=f<=1)
*/

double lfexp(double value, double *iptr);
1
2
frexp(12.0, &exp);// .75, exp: 4
frexp(0.25, &exp);// 0.5, exp: -1

ldexp函数

说明:将小数部分f和整数部分exp组合为,一般而言为f x 2^exp(frexp函数的逆函数)
原型:math.h

1
2
3
4
5
6
/**
* @param {double} f 小数部分
* @param {int} exp 整数部分
* @return {double} f x 2^exp
*/

double ldexp(double f int exp);
1
2
ldexp(.75, 4);// 12.0
ldexp(0.5, -1);// 0.25

modf函数

说明:将一个浮点数的整数部分和小数部分拆解开,返回小数部分,并将整数部分存入第二个参数所指向的变量中
用途:主要供math.h中的其他函数点用,很少在程序中直接使用
原型:math.h

1
2
3
4
5
6
/**
* @param {double} value 原始浮点数
* @param {double *} iptr 存储整数部分的地址
* @return {double} 小数部分
*/

double modf(double value, double *iptr);

23.3.5 幂函数

pow函数

说明:计算x的y次幂
原型:math.h

1
2
3
4
5
6
/**
* @param {double} x 底数
* @param {double} y 指数
* @param {double} x^y
*/

double pow(double x, double y);
1
2
3
pow(3.0, 2.0);// 9.0
pow(3.0, 0.5);// 1.73205
pow(3.0, -3.0);// 0.037037

sqrt函数

说明:计算平方根(算数平方根),sqrt(x)相当于pow(x, 0.5)
原型:math.h

1
2
3
4
5
/**
* @param {double} x 开放数
* @return {double} 平方根
*/

double sqrt(double x);
1
sqrt(3.0);// 1.73205

23.3.6 就近取整函数、绝对值函数和取余函数

ceil函数

说明:向上舍入(计算大于或等于其参数的最小整数)
原型:math.h

1
2
3
4
/**
* @param {double} x
*/

double ceil(double x);

floor函数

说明:向下舍入(计算小于或等于其参数的最大整数)
原型:math.h

1
2
3
4
/**
* @param {double} x
*/

double floor(double x);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 向上取整
ceil(7.1);// 8.0
ceil(7.8);// 8.0
ceil(-7.1);// -7.0

// 向下取整
floor(7.1);// 7.0
floor(7.8);// 7.0
floor(-7.1);// -8.0

/**
* 实现“四舍五入”(标准库没实现)
* @param {double} x 原始的浮点数
* @return {double} 四舍五入后的
*/

double round(double x) {
return x < 0.07 ? ceil(x - 0.5) : floor(x + 0.5);
}

fabs函数

说明:计算参数的绝对值
原型:math.h

1
2
3
4
/**
* @param {double} x 原始浮点数
*/

double fabs(double x);
1
2
fabs(7.1);// 7.1
fabs(-7.1);// 7.1

fmod函数

说明:取余(第一个参数除以第二个参数所得的余数)
注意:%只能用于整数,不能用于浮点数
原型:math.h

1
2
3
4
5
/*
* @param {double} x 被除数
* @param {double} y 除数
*/

double fmod(double x, double y);
1
fmod(5.5, 2.2);// 1.1

23.4 ctype.h:字符处理

说明:ctype.h提供了两类函数
一、 字符测试函数
举例
isdigit函数:用来检测一个字符是否是数字

二、 字符大小写转换函数
举例
toupper函数:用来将一个小写字母转换成大写字母

技巧:建议使用ctype.h中提供的函数而不是用其他手段测试字符或进行大小写转换

  1. 性能更好(大多数是用宏实现的)
  2. 可移植性更好(可以在任何字符集上运行)
  3. 国际化(可以正确运行在世界上不同地点)

特点(参数和返回值类型)ctype.h中的函数都以int类型作为参数,并返回一个int类型的值(C语言可以自动将char类型的参数转换为int类型,或将int类型的返回值转换成char类型)。

23.4.1 字符测试函数

说明:这些函数具有一样的参数类型返回值类型
原型:ctype.h

1
2
3
4
5
/**
* @param {int} c 要测试的字符
* @param {int} 1:测试符合期待;0:测试不符合期待
*/

int 函数名(int c);

字符测试函数列表

字符测试函数 测试类型 备注
isalnum 字母或数字
isalpha 字母
iscntrl 控制字符 包括\0x00~\0x1f\0x7f
isdigit 十进制数字
isgraph 可显示字符(除空格外)
islower 小写字母
isprint 可显示字符(包括空格)
ispunct 标点符号 空格、字母、数字以外的可显示字符
isspace 空白字符 空格、换页符(\f)、换行符(\n)、回车符(\r)、横向制表符(\t)、纵向制表符(\v)
isupper 大写字母
isxdigit 十六进制数字

23.4.2 程序:测试字符测试函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <ctype.h>
#define TEST(f) printf("%6c", f(*p) ? 'x' : ' ');
int main () {
char *p;
printf(" alnum cntrl graph print space xdigit alpha digit lower punc upper\n");
for (p = "azAZ0 !\t"; *p != '0'; p++) {
if (iscntrl(*p)) {
printf("\\x%02x:", *p);
}
else {
printf("%5c:", *p);
}
TEST(isalnum);
TEST(iscntrl);
TEST(isgraph);
TEST(isprint);
TEST(isspace);
TEST(isxdigit);
TEST(isalpha);
TEST(isdigit);
TEST(islower);
TEST(ispunct);
TEST(isupper);
printf("\n");
}
}

Alt text

23.4.3 字符大小写转换函数

tolower函数

说明:返回与作为参数的字母相对应的小写字母
原型:math.h

1
2
3
4
5
/**
* @param {int} c 原始字符(字母)
* @return {int} 对应的小写字母
*/

int tolower(int c);

toupper函数


说明:返回与作为参数的字母相对应的大写字母
原型:math.h

1
2
3
4
5
/**
* @param {int} c 原始字符(字母)
* @return {int} 对应的大写字母
*/

int toupper(int c);

23.4.4 程序:测试大小写转换函数

1
2
3
4
5
6
7
8
9
10
11
#include <ctype.h>
#include <stdio.h>

int main() {
char *p;
for (p = "aA0!"; *p != '\0'; p++) {
printf("tolower('%c') is '%c';\n", *p, tolower(*p));
printf("toupper('%c') is '%c'\n", *p, toupper(*p));
}
return 0;
}

Alt text

23.5 string.h:字符串处理

相关章节:13.5
函数分类:可以分为5类

分类 说明
复制函数 将字符从内存中的一处复制到另一处
拼接函数 向字符串末尾追加字符
比较函数 比较字符数组的函数
搜索函数 在字符数组中搜索特定字符、字符组或字符串
其他函数 初始化字符数组或计算字符串的长度

23.5.1 复制函数

说明:共4个函数,用于将字符(字节)将内存的一处(源)移动到另一处(目的)。要求第一个参数指向目的,第二个参数指向源,并返回第一个参数(即指向目的的指针)。

memcpy函数


说明:从源向目的复制n个字节(当源和目的重叠时无法正常工作)
对源的要求:不要求字符串以空字符结尾,对任意内存块正常工作。
限制:当从一块内存区域复制到另一块可能重叠的内存区域时,不能保证正常工作。
性能:memmove函数快一些
原型:string.h

1
2
3
4
5
6
7
/**
* @param {void *} s1 目的地地址
* @param {void *} s2 源位置地址
* @param {size_t} n 不会复制多于n个字符
* @return {void *} 目的地址
*/

void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
1
2
3
4
5
6
char source[] = {'h', '0', 't', '\0', 't', 'e', 'a'};
char dest[7];

memcpy(dest, source, 3);// h, o, t
memcpy(dest, source, 4);// h, o, t, \0
memcpy(dest, source, 7);// h, o, t, \0, t, e, a

memmove函数


说明:从源向目的复制n个字节(当源和目的重叠时仍然可以正常工作)
对源的要求:不要求字符串以空字符结尾,对任意内存块正常工作。
性能:memcpy函数性能差一些
原型:string.h

1
2
3
4
5
6
/**
* @param {void *} s1 目的地地址
* @param {void *} s2 源位置地址
* @return {void *} 目的地址
*/

void *memmove(void * restrict s1, const void * restrict s2, size_t n);
1
2
3
4
5
6
char source[] = {'h', '0', 't', '\0', 't', 'e', 'a'};
char dest[7];

memmove(dest, source, 3);// h, o, t
memmove(dest, source, 3);// h, o, t, \0
memmove(dest, source, 3);// h, o, t, \0, t, e, a

strcpy函数


说明:将一个以空字符结尾的字符串从源复制到目的,会持续复制字符,直到遇到一个空字符为止。
对源的要求:要求字符串以空字符结尾。
原型:string.h

1
2
3
4
5
6
/**
* @param {void *} s1 目的地地址
* @param {void *} s2 源位置地址
* @return {char *}
*/

char *strcpy(char * restrict s1, const char * restrict s2);
1
2
3
4
char source[] = {'h', '0', 't', '\0', 't', 'e', 'a'};
char dest[7];

strcpy(dest, souce);// h, o, t, \0

strncpy函数


说明:将一个以空字符结尾的字符串从源复制到目的,strcpy函数的增强版
对源的要求:不要求字符串以空字符串结尾,对任意内存块正常工作。
安全:strcpy函数更安全
性能:strcpy差一些
原型:string.h

1
2
3
4
5
6
7
/**
* @param {void *} s1 目的地地址
* @param {void *} s2 源位置地址
* @param {size_t} n 不会复制多于n个字符(如果)
* @return {char *}
*/

char *strncpy(char * restrict s1, const char * restrict s2, size_t n);
1
2
3
4
5
6
char source[] = {'h', '0', 't', '\0', 't', 'e', 'a'};
char dest[7];

strncpy(dest, source, 3);// h, o, t
strncpy(dest, source, 3);// h, o, t, \0
strncpy(dest, source, 3);// h, o, t, \0, \0, \0, \0

23.5.2 拼接函数

strcat函数


说明:将第一个参数追加到第一个参数的末尾

  • 参数:要求两个参数都是以\0结尾的字符串
  • 返回值:返回的字符串会自动在末尾添加\0

原型:string.h

1
2
3
4
5
6
/**
* @param {char *} s1 原本的字符串
* @param {char *} s2 被追加的部分
* @return {char *} 拼接后的字符串(第一个参数的指针)
*/

char *strcat(char *s1, const char * restrict s2);
1
2
char str[7] = "tea";
strcat(str, "bag");// t, e, a, b, a, g, \0

strncat函数


说明:strcat的增强版,第3个参数会限制复制的字符的个数。
原型:string.h

1
2
3
4
5
6
7
/**
* @param {char *} s1 原本的字符串
* @param {char *} s2 被追加的部分
* @param {size_t} n 限制复制的字符的个数
* @return {char *} 拼接后的字符串(第一个参数的指针)
*/

char *strcat(char *s1, const char * restrict s2);
1
2
3
4
5
char str[7] = "tea";

strncat(str, "bag", 2);// t, e, a, b, a, \0
strncat(str, "bag", 3);// t, e, a, b, a, g, \0
strncat(str, "bag", 4);// t, e, a, b, a, g, \0

23.5.3 比较函数

注意:下面5个函数可以分为两类

分组 比较依据 性能
memcmp函数strcmp函数strncmp函数 计算机自身的排序顺序(通常是ACILL)
strcoll函数strxfrm函数 依赖当前的本地化设置

memcpm函数


说明:比较两个字符串的大小(具有限制参与比较的字符个数的参数)
原型:string.h

1
2
3
4
5
6
7
/**
* @param {void *} s1 参与比较的字符串
* @param {void *} s2 参与比较的字符串
* @param {size_t} n 参与比较的字符个数上限
* @return {int} 负整数:s1 < s2; 0:s1 == s2;正整数:s1 > s2
*/

int memcmp(const void *s1, const void *s2, size_t n);
1
2
3
4
5
6
7
8
9
char s1[] == {'b', 'i', 'g', '\0', 'c', 'a', 'r'};
char s2[] == {'b', 'i', 'g', '\0', 'c', 'a', 't'};

// true
if (memcmp(s1, s2, 3) == 0) ...
// true
if (memcmp(s1, s2, 4) == 0) ...
// false
if (memcmp(s1, s2, 7) == 0) ...

strcpm函数


说明:比较两个字符串(不能设置参与比较的字符数上限),在其中一个字符数组遇到\0时停止比较。

  • 参数:必须是以\0结尾的字符串

原型:string.h

1
2
3
4
5
6
/**
* @param {char *} s1 参与比较的字符串
* @param {char *} s2 参与比较的字符串
* @return {int} 负整数:s1 < s2; 0:s1 == s2;正整数:s1 > s2
*/

int strcmp(const char *s1, const char *s2);

strncmp函数


说明:结合memcmpstrcmp,当比较的字符数达到字符数上限或任意一个字符数组中遇到\0时停止比较。
原型:string.h

1
2
3
4
5
6
7
/**
* @param {char *} s1 参与比较的字符串
* @param {char *} s2 参与比较的字符串
* @param {size_t} n 参与比较的字符个数上限
* @return {int} 负整数:s1 < s2; 0:s1 == s2;正整数:s1 > s2
*/

int strncmp(const char *s1, const char *s2, size_t n);
1
2
3
if (strncmp(s1, s2, 3) == 0) ...// true
if (strncmp(s1, s2, 4) == 0) ...// true
if (strncmp(s1, s2, 7) == 0) ...// true

strcoll函数


说明:类似strcmp,不同点在于比较结果依赖本地化设置(通过调用setlocale函数25.1.2)。
缺点:性能差。
应用:适用于那些根据程序运行的地点不同而可能按不同方式比较的程序。
原型:string.h

1
2
3
4
5
6
/**
* @param {char *} s1 参与比较的字符串
* @param {char *} s2 参与比较的字符串
* @return {int} 负整数:s1 < s2; 0:s1 == s2;正整数:s1 > s2
*/

int strcoll(const char *s1, const char *s2);

strxfrm函数


说明:按照本地化设置转换字符串。
技巧:需要考虑本地化时可以配合strcmp来取代strcoll。因为对两个转化后的参数调用strcmp等价直接调用strcoll
原型:string.h

1
2
3
4
5
6
7
/**
* @param {char *} s1 转换后的字符串存储到s1
* @return {char *} s2 需要转换的字符串
* @param {char *} size_t 转换的字符数量上限
* @return {size_t} 转换后字符串的长度
*/

size_t strxfrm(char * restrict s1, const char * restict s2, size_t n);
1
2
3
4
5
6
7
8
size_t len;
char *transformed;
// 获取转换后字符串的长度
len = strxfrm(NULL, original, 0);
// 分配内存
transformed = malloc(len + 1);
// 将转换后的字符串存储到分配的内存中
strxfrm(transformed, original, len);

23.5.4 搜索函数

strchr函数


说明:在字符串中搜索指定字符。
停止搜索时机:遇到首个\0
原型:string.h

1
2
3
4
5
6
/**
* @param {char *} s 字符串
* @param {int} c 要搜索的字符
* @return {char *} 指向s中要搜索的第一个c的指针:搜索到了c;空字符:没有搜索到c
*/

char strchr(const char *s, int c);
1
2
3
4
char *p, str[] = "Form follows function.";
p = strchr(str, 'f');// 找到第一个'f'

p = strchr(p + 1, 'f');// 找到第二个'f'

memchr函数


说明:类似strchr,在字符串中搜索指定字符
停止搜索时机:搜索了指定数量的字符后
用途:适用于不希望对整个字符串进行搜索或搜索的内存块不是以\0结尾时
原型:string.h

1
2
3
4
5
6
7
/**
* @param {void *} s 字符串
* @param {int} c 要搜索的字符
* @param {size_t} n 要搜索的字符数量上限
* @return {void *} 指向s中要搜索的第一个c的指针:搜索到了c;空字符:没有搜索到c
*/

void *memchr(const void *s, int c, size_t n);

strrhrc函数


说明:函数会首先找到字符串末尾的空字符,然后反向查找字符。
原型:string.h

1
2
3
4
5
6
/**
* @param {char *} s1 字符串
* @param {int} c 要搜索的字符
* @return {void *} 指向s中要搜索的第一个c的指针:搜索到了c;空字符:没有搜索到c
*/

char *strrchr(const char * s1, int c);
1
2
3
char *p, str[22] = "Form follows function";
// 反向搜索字符'f'
p = memchr(strr, 'f', sizeof(str));

strpbrk函数


说明:返回指向第一个实际参数中与第二个实参中任意一个字符匹配的最左边一个字符的指针。
更通用:strchr相当于strpbrk的第二个参数字符串中只给一个字符的情况。
原型:string.h

1
2
3
4
5
6
/**
* @param {char *} s1 字符串
* @param {char *} s2 匹配字符集
* @return {char *} 指向匹配到的字符:匹配到;指针:没有匹配到
*/

char *strpbrk(const char *s1, const char *s2);
1
2
3
4
char *p, str[] = "Form follows function.";

// 搜索第一个'm'或'n'
p = strpbrk(str, "mm");

strspn函数


说明:返回字符串中第一个不属于给定字符集中的字符的下标。
原型:string.h

1
2
3
4
5
6
/**
* @param {char *} s1 字符串
* @param {char *} s2 字符集合
* @return {size_t} 字符的下标
*/

size_t strspn(const char *s1, const char *s2);

strcspn函数


说明:返回字符串中第一个属于给定字符集中的字符的下标。
原型:string.h

1
2
3
4
5
6
/**
* @param {char *} s1 字符串
* @param {char *} s2 字符集合
* @return {size_t} 字符的下标
*/

size_t strcspn(const char *s1, const char *s2);
1
2
3
4
5
6
7
size_t len;
char str[] = "Form follows function.";

len = strspn(str, "morF");// 4
len = strspn(str, " \t\n");// 0
len = strcspn(str, "morF");// 0
len = strcspn(str, "morF");// 4

strstr函数


说明:在第一个参数(字符串)中搜索能匹配第二个参数(字符串)的子串,并返回找到的第一处匹配子串的指针。
原型:string.h

1
2
3
4
5
/**
* @param {char *} s1 字符串
* @param {char *} s2 字符串
*/

char *strstr(const char *s1, const char *s2);
1
2
3
4
char *p, str[] = "Form follows function.";

// 在str中搜索"fun"
p = strstr(str, "fun");

strtok函数


说明:分割出一段子字符串。
原理:在s1中搜索,按照s2指定的分隔符找出一系列非空字符(不包含s2中指定的字符)。strtok函数会写入一个\0来标记字符序列的末尾,并返回指向这个序列的首字符的指针。
原型:string.h

1
2
3
4
5
6
/**
* @param {char *} s1 字符串
* @param {char *} s2 字符串(要作为分割字符的字符集合)
* @return {char *} 指向新分割出来的子字符串的指针(指向首字符)
*/

char *strtok(char * restrict s1, const char * restrict s2);

(1) 原始字符串状态

1
char *p, str[] = " Apri1  28,1990";
A p r i 1 2 8 , 1 9 9 8 \0

(2) 月

1
2
3
// 分割出第一个序列,使用" \t"中的字符作为分隔符
// 月
p = strtok(str, " \t");
A p r i 1 \0 2 8 , 1 9 9 8 \0

(3) 日

1
2
3
// 从上次结束的位置继续查找
// 日
p = strtok(NULL, " \t");
A p r i 1 \0 2 8 \0 1 9 9 8 \0

(4) 年

1
2
3
// 从上次结束的位置继续查找
// 年
p = strtok(NULL, " \t");
A p r i 1 \0 2 8 \0 1 9 9 8 \0

23.5.5 其他函数

memset函数


说明:将一个字符的多个副本存储到指定区域。
应用:将数组元素全部初始化为0
原型:string.h

1
2
3
4
5
6
7
/**
* @param {void *} s 指向用来存储字符副本的空间
* @param {int} c 用于填充的字符
* @param {size_t} n 从s指向的地址往后填充空间大小(字节)
* @return {void *} 第一个参数(空间地址)
*/

void *memset(void *s, int c, size_t n);
1
2
3
4
5
// 为p指向的内存的N哥字节存储空格
memset(p, ' ', N);

// 将数组a初始化为0
memset(a, 0, sizeof(a));

strlen函数


说明:返回字符串的长度,不计算字符串末尾的\0
原型:string.h

1
2
3
4
5
/**
* @param {char *} s 字符串
* @return {size_t} 字符串的常速
*/

size_t strlen(const char* s);

strerror函数

说明:24.2
原型:errno.h