首页
前端面试题
前端报错总结
电子书
更多
插件下载
Search
1
JavaScript基础(二)操作符 流程控制
42 阅读
2
HTML基础
20 阅读
3
Vue基础
17 阅读
4
wctype.h
14 阅读
5
Vue2(知识点)
13 阅读
默认分类
HTML CSS
HTML基础
CSS
HTML5 CSS3
javaScript
javaScript基础
javaScript高级
Web APIs
jQuery
js小总结
WEB开发布局
Vue
PS切图
数据可视化
Git使用
Uniapp
c语言入门
标准库
嵌入式
登录
Search
liuxiaobai
累计撰写
108
篇文章
累计收到
12
条评论
首页
栏目
默认分类
HTML CSS
HTML基础
CSS
HTML5 CSS3
javaScript
javaScript基础
javaScript高级
Web APIs
jQuery
js小总结
WEB开发布局
Vue
PS切图
数据可视化
Git使用
Uniapp
c语言入门
标准库
嵌入式
页面
前端面试题
前端报错总结
电子书
插件下载
搜索到
41
篇与
的结果
2023-09-20
string.h
string.hstring.h主要定义了字符串处理函数和内存操作函数。字符串处理函数以下字符串处理函数,详见《字符串》一章。strcpy():复制字符串。strncpy():复制字符串,有长度限制。strcat():连接两个字符串。strncat():连接两个字符串,有长度限制。strcmp():比较两个字符串。strncmp():比较两个字符串,有长度限制。strlen():返回字符串的字节数。strchr(),strrchr()strchr()和strrchr()都用于在字符串中查找指定字符。不同之处是,strchr()从字符串开头开始查找,strrchr()从字符串结尾开始查找,函数名里面多出来的那个r表示 reverse(反向)。char* strchr(char* str, int c); char* strrchr(char *str, int c);它们都接受两个参数,第一个参数是字符串指针,第二个参数是所要查找的字符。一旦找到该字符,它们就会停止查找,并返回指向该字符的指针。如果没有找到,则返回 NULL。下面是一个例子。char *str = "Hello, world!"; char *p; p = strchr(str, ','); // p 指向逗号的位置 p = strrchr(str, 'o'); // p 指向 world 里面 o 的位置strspn(),strcspn()strspn()用来查找属于指定字符集的字符串长度,strcspn()正好相反,用来查找不属于指定字符集的字符串长度。size_t strspn(char* str, const char* accept); size_t strcspn(char *str, const char *reject);这两个函数接受两个参数,第一个参数是源字符串,第二个参数是由指定字符组成的字符串。strspn()从第一个参数的开头开始查找,一旦发现第一个不属于指定字符集范围的字符,就停止查找,返回到目前为止的字符串长度。如果始终没有不在指定字符集的字符,则返回第一个参数字符串的长度。strcspn()则是一旦发现第一个属于指定字符集范围的字符,就停止查找,返回到目前为止的字符串长度。如果始终没有发现指定字符集的字符,则返回第一个参数字符串的长度。char str[] = "hello world"; int n; n = strspn(str1, "aeiou"); printf("%d\n", n); // n == 0 n = strcspn(str1, "aeiou"); printf("%d\n", n); // n == 1上面示例中,第一个n等于0,因为0号位置的字符h就不属于指定字符集aeiou,可以理解为开头有0个字符属于指定字符集。第二个n等于1,因为1号位置的字符e属于指定字符集aeiou,可以理解为开头有1个字符不属于指定字符集。strpbrk()strpbrk()在字符串中搜索指定字符集的任一个字符。char* strpbrk(const char* s1, const char* s2);它接受两个参数,第一个参数是源字符串,第二个参数是由指定字符组成的字符串。它返回一个指向第一个匹配字符的指针,如果未找到匹配字符,则返回 NULL。char* s1 = "Hello, world!"; char* s2 = "dow!"; char* p = strpbrk(s1, s2); printf("%s\n", p); // "o, world!"上面示例中,指定字符集是“dow!”,那么s1里面第一个匹配字符是“Hello”的“o”,所以指针p指向这个字符。输出的话,就会输出从这个字符直到字符串末尾的“o, world!”。strstr()strstr()在一个字符串里面,查找另一个字符串。char *strstr( const char* str, const char* substr );它接受两个参数,第一个参数是源字符串,第二个参数是所要查找的子字符串。如果匹配成功,就返回一个指针,指向源字符串里面的子字符串。如果匹配失败,就返回 NULL,表示无法找到子字符串。char* str = "The quick brown fox jumped over the lazy dogs."; char* p = strstr(str, "lazy"); printf("%s\n", p == NULL ? "null": p); // "lazy dogs."上面示例中,strstr()用来在源字符串str里面,查找子字符串lazy。从返回的指针到字符串结尾,就是“lazy dogs.”。strtok()strtok()用来将一个字符串按照指定的分隔符(delimiter),分解成一系列词元(tokens)。char* strtok(char* str, const char* delim);它接受两个参数,第一个参数是待拆分的字符串,第二个参数是指定的分隔符。它返回一个指针,指向分解出来的第一个词元,并将词元结束之处的分隔符替换成字符串结尾标志\0。如果没有待分解的词元,它返回 NULL。如果要遍历所有词元,就必须循环调用,参考下面的例子。strtok()的第一个参数如果是 NULL,则表示从上一次strtok()分解结束的位置,继续往下分解。#include <stdio.h> #include <string.h> int main(void) { char string[] = "This is a sentence with 7 tokens"; char* tokenPtr = strtok(string, " "); while (tokenPtr != NULL) { printf("%s\n", tokenPtr); tokenPtr = strtok(NULL, " "); } }上面示例将源字符串按照空格,分解词元。它的输出结果如下。This is a sentence with 7 tokens注意,strtok()会修改原始字符串,将所有分隔符都替换成字符串结尾符号\0。因此,最好生成一个原始字符串的拷贝,然后再对这个拷贝执行strtok()。strcoll()strcoll()用于比较两个启用了本地化设置的字符串,用法基本与strcmp()相同。int strcoll(const char *s1, const char *s2);请看下面的示例。setlocale(LC_ALL, ""); // 报告 é > f printf("%d\n", strcmp("é", "f")); // 报告 é < f printf("%d\n", strcoll("é", "f"));上面示例比较带重音符号的é与f,strcmp()会返回é大于f,而strcoll()就会正确识别é排在f前面,所以小于f。注意,在比较之前,需要使用setlocale(LC_ALL, ""),启用本地化设置。strxfrm()strxfrm()将一个本地化字符串转成可以使用strcmp()进行比较的形式,相当于strcoll()内部的第一部分操作。size_t strxfrm( char * restrict s1, const char * restrict s2, size_t n );它接受三个参数,将第二个参数s2转为可以使用strcmp()比较的形式,并将结果存入第一个参数s1。第三个参数n用来限定写入的字符数,防止超出s1的边界。它返回转换后的字符串长度,不包括结尾的终止符。如果第一个参数是 NULL,第三个参数是0,则不进行实际的转换,只返回转换后所需的字符串长度。下面的示例是用这个函数自己实现一个strcoll()。int my_strcoll(char* s1, char* s2) { int len1 = strxfrm(NULL, s1, 0) + 1; int len2 = strxfrm(NULL, s2, 0) + 1; char *d1 = malloc(len1); char *d2 = malloc(len2); strxfrm(d1, s1, len1); strxfrm(d2, s2, len2); int result = strcmp(d1, d2); free(d2); free(d1); return result; }上面示例中,先为两个进行比较的本地化字符串,分配转换后的存储空间,使用strxfrm()将它们转为可比较的形式,再用strcmp()进行比较。strerror()strerror()函数返回特定错误的说明字符串。char *strerror(int errornum);它的参数是错误的编号,由errno.h定义。返回值是一个指向说明字符串的指针。// 输出 No such file or directory printf("%s\n", strerror(2));上面示例输出2号错误的说明字符“No such file or directory“。下面的例子是自定义报错信息。#include <stdio.h> #include <string.h> #include <errno.h> int main(void) { FILE* fp = fopen("NONEXISTENT_FILE.TXT", "r"); if (fp == NULL) { char* errmsg = strerror(errno); printf("Error %d opening file: %s\n", errno, errmsg); } }上面示例中,通过strerror(errno)拿到当前的默认报错信息,其中errno是errno.h定义的宏,表示当前的报错编号。然后,再输出一条自定义的报错信息。内存操作函数以下内存操作函数,详见《内存管理》一章。memcpy():内存复制函数。memmove():内存复制函数(允许重叠)。memcmp():比较两个内存区域。memchr()memchr()用于在内存区域中查找指定字符。void* memchr(const void* s, int c, size_t n);它接受三个参数,第一个参数是内存区域的指针,第二个参数是所要查找的字符,第三个参数是内存区域的字节长度。一旦找到,它就会停止查找,并返回指向该位置的指针。如果直到检查完指定的字节数,依然没有发现指定字符,则返回 NULL。下面是一个例子。char *str = "Hello, world!"; char *p; p = memchr(str, '!', 13); // p 指向感叹号的位置memset()memset()将一段内存全部格式化为指定值。void* memset(void* s, int c, size_t n);它的第一个参数是一个指针,指向内存区域的开始位置,第二个参数是待写入的字符值,第三个参数是一个整数,表示需要格式化的字节数。它返回第一个参数(指针)。memset(p, ' ', N);上面示例中,p 是一个指针,指向一个长度为 N 个字节的内存区域。memset()将该块内存区域的每个字节,都改写为空格字符。下面是另一个例子。char string1[15] = "BBBBBBBBBBBBBB"; // 输出 bbbbbbbBBBBBBB printf("%s\n", (char*) memset(string1, 'b', 7));memset()的一个重要用途,就是将数组成员全部初始化为0。memset(arr, 0, sizeof(arr));下面是将 Struct 结构都初始化为0的例子。struct banana { float ripeness; char *peel_color; int grams; }; struct banana b; memset(&b, 0, sizeof b); b.ripeness == 0.0; // True b.peel_color == NULL; // True b.grams == 0; // True上面示例,将 Struct banana 的实例 b 的所有属性都初始化为0。其他函数void* memset(void* a, int c, size_t n); size_t strlen(const char* s);
2023年09月20日
1 阅读
0 评论
0 点赞
2023-09-20
stdlib.h
stdlib.h类型别名和宏stdlib.h 定义了下面的类型别名。size_t:sizeof 的返回类型。wchar_t:宽字符类型。stdlib.h 定义了下面的宏。NULL:空指针。EXIT_SUCCESS:函数运行成功时的退出状态。EXIT_FAILURE:函数运行错误时的退出状态。RAND_MAX:rand() 函数可以返回的最大值。MB_CUR_MAX:当前语言环境中,多字节字符占用的最大字节数。abs(),labs(),llabs()这三个函数用于计算整数的绝对值。abs()用于 int 类型,labs()用于 long int 类型,llabs()用于 long long int 类型。int abs(int j); long int labs(long int j); long long int llabs(long long int j);下面是用法示例。// 输出 |-2| = 2 printf("|-2| = %d\n", abs(-2)); // 输出 |4| = 4 printf("|4| = %d\n", abs(4));div(),ldiv(),lldiv()这三个函数用来计算两个参数的商和余数。div()用于 int 类型的相除,ldiv()用于 long int 类型的相除,lldiv()用于 long long int 类型的相除。div_t div(int numer, int denom); ldiv_t ldiv(long int numer, long int denom); lldiv_t lldiv(long long int numer, long long int denom);这些函数把第2个参数(分母)除以第1个参数(分子),产生商和余数。这两个值通过一个数据结构返回,div()返回 div_t 结构,ldiv()返回 ldiv_t 结构,lldiv()返回 lldiv_t 结构。这些结构都包含下面两个字段,int quot; // 商 int rem; // 余数它们完整的定义如下。typedef struct { int quot, rem; } div_t; typedef struct { long int quot, rem; } ldiv_t; typedef struct { long long int quot, rem; } lldiv_t;下面是一个例子。div_t d = div(64, -7); // 输出 64 / -7 = -9 printf("64 / -7 = %d\n", d.quot); // 输出 64 % -7 = 1 printf("64 %% -7 = %d\n", d.rem);字符串转成数值a 系列函数stdlib.h定义了一系列函数,可以将字符串转为数字。atoi():字符串转成 int 类型。atof():字符串转成 double 类型。atol():字符串转成 long int 类型。atoll():字符串转成 long long int 类型。它们的原型如下。int atoi(const char* nptr); double atof(const char* nptr); long int atol(const char* nptr); long long int atoll(const char* nptr);上面函数的参数都是一个字符串指针,字符串开头的空格会被忽略,转换到第一个无效字符处停止。函数名称里面的a代表 ASCII,所以atoi()的意思是“ASCII to int”。它们返回转换后的数值,如果字符串无法转换,则返回0。下面是用法示例。atoi("3490") // 3490 atof("3.141593") // 3.141593如果参数是数字开头的字符串,atoi()会只转换数字部分,比如atoi("42regular")会返回整数42。如果首字符不是数字,比如“hello world”,则会返回0。str 系列函数(浮点数转换)stdlib.h还定义了一些更强功能的浮点数转换函数。strtof():字符串转成 float 类型。strtod():字符串转成 double 类型。strtold():字符串转成 long double 类型。它们的原型如下。float strtof( const char* restrict nptr, char** restrict endptr ); double strtod( const char* restrict nptr, char** restrict endptr ); long double strtold( const char* restrict nptr, char** restrict endptr );它们都接受两个参数,第一个参数是需要转换的字符串,第二个参数是一个指针,指向原始字符串里面无法转换的部分。nptr:待转换的字符串(起首的空白字符会被忽略)。endprt:一个指针,指向不能转换部分的第一个字符。如果字符串可以完全转成数值,该指针指向字符串末尾的终止符\0。这个参数如果设为 NULL,就表示不需要处理字符串剩余部分。它们的返回值是已经转换后的数值。如果字符串无法转换,则返回0。如果转换结果发生溢出,errno 会被设置为 ERANGE。如果值太大(无论是正数还是负数),函数返回HUGE_VAL;如果值太小,函数返回零。char *inp = " 123.4567abdc"; char *badchar; double val = strtod(inp, &badchar); printf("%f\n", val); // 123.456700 printf("%s\n", badchar); // abdc字符串可以完全转换的情况下,第二个参数指向\0,因此可以用下面的写法判断是否完全转换。if (*endptr == '\0') { // 完全转换 } else { // 存在无法转换的字符 }如果不关心没有转换的部分,则可以将 endptr 设置为 NULL。这些函数还可以将字符串转换为特殊值 Infinity 和 NaN。如果字符串包含 INF 或 INFINITY(大写或小写皆可),则将转换为 Infinity;如果字符串包含 NAN,则将返回 NaN。str 系列函数(整数转换)str 系列函数也有整数转换的对应函数。strtol():字符串转成 long int 类型。strtoll():字符串转成 long long int 类型。strtoul():字符串转成 unsigned long int 类型。strtoull():字符串转成 unsigned long long int 类型。它们的原型如下。long int strtol( const char* restrict nptr, char** restrict endptr, int base ); long long int strtoll( const char* restrict nptr, char** restrict endptr, int base ); unsigned long int strtoul( const char* restrict nptr, char** restrict endptr, int base ); unsigned long long int strtoull( const char* restrict nptr, char** restrict endptr, int base );它们接受三个参数。(1)nPtr:待转换的字符串(起首的空白字符会被忽略)。(2)endPrt:一个指针,指向不能转换部分的第一个字符。如果字符串可以完全转成数值,该指针指向字符串末尾的终止符\0。这个参数如果设为 NULL,就表示不需要处理字符串剩余部分。(3)base:待转换整数的进制。这个值应该是2到36之间的整数,代表相应的进制,如果是特殊值0,表示让函数根据数值的前缀,自己确定进制,即如果数字有前缀0,则为八进制,如果数字有前缀0x或0X,则为十六进制。它们的返回值是转换后的数值,如果转换不成功,返回0。下面是转换十进制整数的例子。char* s = "3490"; unsigned long int x = strtoul(u, NULL, 10); printf("%lu\n", x); // 3490下面是转换十六进制整数的例子。char* end; long value = strtol("0xff", &end, 16); printf("%ld\n", value); // 255 printf("%s\n", end); // 无内容 value = strtol("0xffxx", &end, 16); printf("%ld\n", value); // 255 printf("%s\n", end); // xx上面示例中,strtol()可以指定字符串包含的是16进制整数。不能转换的部分,可以使用指针end进行访问。下面是转换二进制整数的例子。char* s = "101010"; unsigned long int x = strtoul(s, NULL, 2); printf("%lu\n", x); // 42下面是让函数自行判断整数进制的例子。#include <stdio.h> #include <stdlib.h> int main(void) { const char* string = "-1234567abc"; char* remainderPtr; long x = strtol(string, &remainderPtr, 0); printf("%s\"%s\"\n%s%ld\n%s\"%s\"\n", "The original string is ", string, "The converted value is ", x, "The remainder of the original string is ", remainderPtr ); }上面代码的输出结果如下。The original string is "-1234567abc" The converted value is -1234567 The remainder of the original string is "abc"如果被转换的值太大,strtol()函数在errno中存储ERANGE这个值,并返回LONG_MIN(原值为负数)或LONG_MAX(原值为正数),strtoul()则返回ULONG_MAX。rand()rand()函数用来生成 0~RAND_MAX 之间的随机整数。RAND_MAX是一个定义在stdlib.h里面的宏,通常等于 INT_MAX。// 原型 int rand(void); // 示例 int x = rand();如果希望获得整数 N 到 M 之间的随机数(包括 N 和 M 两个端点值),可以使用下面的写法。int x = rand() % (M - N + 1) + N;比如,1 到 6 之间的随机数,写法如下。int x = rand() % 6 + 1;获得浮点数的随机值,可以使用下面的写法。// 0 到 0.999999 之间的随机数 printf("0 to 0.99999: %f\n", rand() / ((float)RAND_MAX + 1)); // n 到 m 之间的随机数: // n + m * (rand() / (float)RAND_MAX) printf("10.5 to 15.7: %f\n", 10.5 + 5.2 * rand() / (float)RAND_MAX);上面示例中,由于rand()和RAND_MAX都是 int 类型,要用显示的类型转换转为浮点数。srand()rand()是伪随机数函数,为了增加随机性,必须在调用它之前,使用srand()函数重置一下种子值。srand()函数接受一个无符号整数(unsigned int)作为种子值,没有返回值。void srand(unsigned int seed);通常使用time(NULL)函数返回当前距离时间纪元的秒数,作为srand()的参数。#include <time.h> srand((unsigned int) time(NULL));上面代码中,time()的原型定义在头文件time.h里面,返回值的类型是类型别名time_t,具体的类型与系统有关,所以要强制转换一下类型。time()的参数是一个指针,指向一个具体的 time_t 类型的时间值,这里传入空指针NULL作为参数,由于 NULL 一般是0,所以也可以写成time(0)。abort()abort()用于不正常地终止一个正在执行的程序。使用这个函数的目的,主要是它会触发 SIGABRT 信号,开发者可以在程序中为这个信号设置一个处理函数。void abort(void);该函数没有参数。exit(),quick_exit(),_Exit()这三个函数都用来退出当前正在执行的程序。void exit(int status); void quick_exit(int status); void _Exit(int status);它们都接受一个整数,表示程序的退出状态,0是正常退出,非零值表示发生错误,可以使用宏EXIT_SUCCESS和EXIT_FAILURE当作参数。它们本身没有返回值。它们的区别是,退出时所做的清理工作不同。exit()是正常退出,系统会做完整的清理,比如更新所有文件流,并且删除临时文件。quick_exit()是快速退出,系统的清理工作稍微少一点。_Exit()是立即退出,不做任何清理工作。下面是一些用法示例。exit(EXIT_SUCCESS); quick_exit(EXIT_FAILURE); _Exit(2);atexit(),at_quick_exit()atexit()用来登记当前程序退出时(调用exit()或main()正常退出),所要执行的其他函数。at_quick_exit()则是登记使用quick_exit()方法退出当前程序时,所要执行的其他函数。exit()只能触发atexit()登记的函数,quick_exit()只能触发at_quick_exit()登记的函数。int atexit(void (*func)(void)); int at_quick_exit(void (*func)(void));它们的参数是要执行的函数地址,即函数名。它们的返回值都是调用成功时返回0,调用失败时返回非零值。下面是一个例子。void sign_off(void); void too_bad(void); int main(void) { int n; atexit(sign_off); /* 注册 sign_off()函数 */ puts("Enter an integer:"); if (scanf("%d", &n) != 1) { puts("That's no integer!"); atexit(too_bad); /* 注册 too_bad()函数 */ exit(EXIT_FAILURE); } printf("%d is %s.\n", n, (n % 2 == 0) ? "even" : "odd"); return 0; } void sign_off(void) { puts("sign_off"); } void too_bad(void) { puts("too bad"); }上面示例中,用户输入失败时,会调用sign_off()和too_bad()函数;但是输入成功时只会调用sign_off()。因为只有输入失败时,才会进入if语句登记too_bad()。另外,如果有多条atexit()语句,函数退出时最先调用的,是最后一个登记的函数。atexit()登记的函数(如上例的sign_off和too_bad)应该不带任何参数且返回类型为void。通常,这些函数会执行一些清理任务,例如删除临时文件或重置环境变量。at_quick_exit()也是同样的规则,下面是一个例子。void exit_handler_1(void) { printf("1\n"); } void exit_handler_2(void) { printf("2\n"); } int main(void) { at_quick_exit(exit_handler_1); at_quick_exit(exit_handler_2); quick_exit(0); }执行上面的示例,命令行会先输出2,再输出1。getenv()getenv()用于获取环境变量的值。环境变量是操作系统提供的程序之外的一些环境参数。char* getenv(const char* name);它的参数是一个字符串,表示环境变量名。返回值也是一个字符串,表示环境变量的值。如果指定的环境变量不存在,则返回 NULL。下面是输出环境变量$PATH的值的例子。printf("PATH is %s\n", getenv("PATH"));system()system()函数用于执行外部程序。它会把它的参数字符串传递给操作系统,让操作系统的命令处理器来执行。void system( char const * command );这个函数的返回值因编译器而异。但是标准规定,如果 NULL 作为参数,表示询问操作系统,是否有可用的命令处理器,如果有的话,返回一个非零值,否则返回零。下面是执行ls命令的例子。system("ls -l"); 内存管理函数stdlib.h 提供了一些内存操作函数,下面几个函数详见《内存管理》一章,其余在本节介绍。malloc():分配内存区域calloc():分配内存区域。realloc():调节内存区域大小。free():释放内存区域。aligned_alloc()很多系统有内存对齐的要求,即内存块的大小必须是某个值(比如64字节)的倍数,这样有利于提高处理速度。aligned_alloc()就用于分配满足内存对齐要求的内存块,它的原型如下。void* aligned_alloc(size_t alignment, size_t size);它接受两个参数。alignment:整数,表示内存对齐的单位大小,一般是2的整数次幂(2、4、8、16……)。size:整数,表示内存块的大小。分配成功时,它返回一个无类型指针,指向新分配的内存块。分配失败时,返回 NULL。char* p = aligned_alloc(64, 256);上面示例中,aligned_alloc()分配的内存块,单位大小是64字节,要分配的字节数是256字节。qsort()qsort()用来快速排序一个数组。它对数组成员的类型没有要求,任何类型数组都可以用这个函数排序。void qsort( void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *) );该函数接受四个参数。base:指向要排序的数组开始位置的指针。nmemb:数组成员的数量。size:数组每个成员占用的字节长度。compar:一个函数指针,指向一个比较两个成员的函数。比较函数compar将指向数组两个成员的指针作为参数,并比较两个成员。如果第一个参数小于第二个参数,该函数应该返回一个负值;如果两个函数相等,返回0;如果第一个参数大于第二个参数,应该返回一个正数。下面是一个用法示例。#include <stdio.h> #include <stdlib.h> int compar(const void* elem0, const void* elem1) { const int* x = elem0; const int* y = elem1; return *x - *y; } int main(void) { int a[9] = {14, 2, 3, 17, 10, 8, 6, 1, 13}; qsort(a, 9, sizeof(int), compar); for (int i = 0; i < 9; i++) printf("%d ", a[i]); putchar('\n'); }执行上面示例,会输出排序好的数组“1 2 3 6 8 10 13 14 17”。bsearch()bsearch()使用二分法搜索,在数组中搜索一个值。它对数组成员的类型没有要求,任何类型数组都可以用这个函数搜索值。注意,该方法只对已经排序好的数组有效。void *bsearch( const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void *, const void *) );这个函数接受5个参数。key:指向要查找的值的指针。base:指向数组开始位置的指针,数组必须已经排序。nmemb:数组成员的数量。size:数组每个成员占用的字节长度。compar:指向一个将待查找值与其他值进行比较的函数的指针。比较函数compar将待查找的值作为第一个参数,将要比较的值作为第二个参数。如果第一个参数小于第二个参数,该函数应该返回一个负值;如果两个参数相等,返回0;如果第一个参数大于第二个参数,返回一个正值。如果找到待查找的值,bsearch()返回指向该值的指针,如果找不到,返回 NULL。下面是一个用法示例。#include <stdio.h> #include <stdlib.h> int compar(const void *key, const void *value) { const int* k = key; const int* v = value; return *k - *v; } int main(void) { int a[9] = {2, 6, 9, 12, 13, 18, 20, 32, 47}; int* r; int key; key = 12; // 包括在数组中 r = bsearch(&key, a, 9, sizeof(int), compar); printf("Found %d\n", *r); key = 30; // 不包括在数组中 r = bsearch(&key, a, 9, sizeof(int), compar); if (r == NULL) printf("Didn't find 30\n"); return 0; }执行上面的示例,会输出下面的结果。Found 12 Didn't find 30多字节字符函数stdlib.h 提供了下面的函数,用来操作多字节字符,详见《多字节字符》一章。mblen():多字节字符的字节长度。mbtowc():将多字节字符转换为宽字符。wctomb():将宽字符转换为多字节字符。mbstowcs():将多字节字符串转换为宽字符串。wcstombs():将宽字符串转换为多字节字符串。
2023年09月20日
6 阅读
0 评论
0 点赞
2023-09-20
stdio.h
stdio.hstdio.h是 C 语言的标准 I/O 库,用于读取和写入文件,也用于控制台的输入和输出。标准 I/O 函数以下函数用于控制台的输入和输出。printf():输出到控制台,详见《基本语法》一章。scanf():从控制台读取输入,详见《I/O 函数》一章。getchar():从控制台读取一个字符,详见《I/O 函数》一章。putchar():向控制台写入一个字符,详见《I/O 函数》一章。gets():从控制台读取整行输入(已废除),详见《I/O 函数》一章。puts():向控制台写入一个字符串,详见《I/O 函数》一章。文件操作函数以下函数用于文件操作,详见《文件操作》一章。fopen():打开文件。fclose():关闭文件。freopen():打开一个新文件,关联一个已经打开的文件指针。fprintf():输出到文件。fscanf():从文件读取数据。getc():从文件读取一个字符。fgetc():从文件读取一个字符。putc():向文件写入一个字符。fputc():向文件写入一个字符。fgets():从文件读取整行。fputs():向文件写入字符串。fread():从文件读取二进制数据。fwrite():向文件写入二进制数据。fseek():将文件内部指针移到指定位置。ftell():获取文件内部指针的当前位置。rewind():将文件内部指针重置到文件开始处。fgetpos():获取文件内部指针的当前位置。fsetpos():设置文件内部指针的当前位置。feof():判断文件内部指针是否指向文件结尾。ferror():返回文件错误指示器的状态。clearerr():重置文件错误指示器。remove():删除文件。rename():文件改名,以及移动文件。字符串操作函数以下函数用于操作字符串,详见《字符串操作》一章。sscanf():从字符串读取数据,详见《I/O 函数》一章。sprintf():输出到字符串。snprintf():输出到字符串的更安全版本,指定了输出字符串的数量。tmpfile()tmpfile()函数创建一个临时文件,该文件只在程序运行期间存在,除非手动关闭它。它的原型如下。FILE* tmpfile(void);tmpfile()返回一个文件指针,可以用于访问该函数创建的临时文件。如果创建失败,返回一个空指针 NULL。FILE* tempptr; tempptr = tmpfile();调用close()方法关闭临时文件后,该文件将被自动删除。tmpfile()有两个缺点。一是无法知道临时文件的文件名,二是无法让该文件成为永久文件。tmpnam()tmpname()函数为临时文件生成一个名字,确保不会与其他文件重名。它的原型如下。char* tmpname(char* s);它的参数是一个字符串变量,tmpnam()会把临时文件的文件名复制到这个变量里面,并返回指向该字符串变量的指针。如果生成文件名失败,tmpnam()返回空指针 NULL。char filename[L_tmpnam]; if (tmpnam(filename) != NULL) // 输出诸如 /tmp/filew9PMuZ 的文件名 printf("%s\n", filename); else printf("Something wrong!\n");上面示例中,L_tmpnam是stdio.h定义的一个宏,指定了临时文件的文件名长度。tmpname()的参数也可以是一个空指针 NULL,同样返回指向文件名字符串的指针。char* filename; filename = tmpnam(NULL);上面示例中,变量filename就是tmpnam()生成的文件名。该函数只是生成一个文件名,稍后可以使用fopen()打开该文件并使用它。fflush()fflush()用于清空缓存区。它接受一个文件指针作为参数,将缓存区内容写入该文件。fflush(fp);如果不需要保存缓存区内容,则可以传入空指针 NULL。fflush(NULL);如果清空成功,fflush()返回0,否则返回 EOF。注意,fflush()一般只用来清空输出缓存区(比如写文件)。如果使用它来清空输入缓存区(比如读文件),属于未定义行为。fflush()的一个用途是不等回车键,就强迫输出缓存区。大多数系统都是行缓存,这意味着只有遇到回车键(或者缓存区满了,或者文件读到结尾),缓存区的内容才会输出,fflush()可以不等回车键,立即输出。for (int i = 9; i >= 0; i--) { printf("\r%d", i); fflush(stdout); sleep(1); }上面示例是一个倒计时效果,\r是回车键,表示每轮循环都会回到当前行的行首,等于删除上一轮循环的输出。fflush(stdout)表示立即将缓存输出到显示器,这一行是必需的,否则由于上一行的输出没有回车键,不会触发缓存输出,屏幕上不会显示任何内容,只会等到程序运行结束再一次性输出。setvbuf()setvbuf()函数用于定义某个字节流应该如何缓存。它可以接受四个参数。int setvbuf(FILE* stream, char* buffer, int mode, size_t size)第一个参数stream是文件流。第二个参数buffer是缓存区的地址。第三个参数mode指定缓存的行为模式,它是下面三个宏之一,这些宏都定义在stdio.h。_IOFBF:满缓存。当缓存为空时,才从流读入数据;当缓存满了,才向流写入数据。一般情况下,这是默认设置。_IOLBF:行缓存。每次从流读入一行数据,或向流写入一行数据,即以行为单位读写缓存。_IONBF:无缓存。不使用缓存区,直接读写设备。第四个参数size指定缓存区的大小。较大的缓存区提供更好的性能,而较小的缓存区可以节省空间。stdio.h提供了一个宏BUFSIZ,表示系统默认的缓存区大小。它的意义在于,使得用户可以在打开一个文件之前,定义自己的文件缓冲区,而不必使用fopen()函数打开文件时设定的默认缓冲区。char buffer[N]; setvbuf(stream, buffer, _IOFBF, N);上面示例设置文件流stream的缓存区从地址buffer开始,大小为N,模式为_IOFBF。setvbuf()的第二个参数可以为空指针 NULL。这样的话,setvbuf()会自己创建一个缓存区。注意,setvbuf()的调用必须在对文件流执行任何操作之前。如果调用成功,setvbuf()的返回值为0,否则返回非零值。下面的例子是将缓存区调整为行缓存。FILE *fp; char lineBuf[1024]; fp = fopen("somefile.txt", "r"); setvbuf(fp, lineBuf, _IOLBF, 1024);setbuf()setbuf()是setvbuf()的早期版本,可以视为后者的简化版本,也用来定义某个字节流的缓存区。void setbuf(FILE* stream, char* buffer);它的第一个参数stream是文件流,第二个参数buffer是缓存区的地址。它总是可以改写成setvbuf()。char buffer[BUFSIZ]; setbuf(stream, buffer); // 等同于 setvbuf(stream, buffer, _IOFBF, BUFSIZ);上面示例中,BUFSIZ是stdio.h定义的宏,表示系统默认的缓存区大小。setbuf()函数没有返回值。setbuf()的第二个参数如果设置为 NULL,表示不进行缓存。setbuf(stdout, NULL); // 等同于 setvbuf(stdout, NULL, _IONBF, 0);ungetc()ungetc()将从缓存里面读取的上一个字符,重新放回缓存,下一个读取缓存的操作会从这个字符开始。有些操作需要了解下一个字符是什么,再决定应该怎么处理,这时这个函数就很有用。它的原型如下。int ungetc(int c, FILE *stream);它的第一个参数是一个字符变量,第二个参数是一个打开的文件流。它的返回值是放回缓存的那个字符,操作失败时,返回 EOF。int ch = fgetc(fp); if (isdigit(ch)) { ch = fgetc(fp); } ungetc(ch, fp);上面示例中,如果读取的字符不是数字,就将其放回缓存。perror()perror()用于在 stderr 的错误信息之前,添加一个自定义字符串。void perror(const char *s);该函数的参数就是在报错信息前添加的字符串。它没有返回值。#include <stdio.h> #include <stdlib.h> #include <math.h> #include <errno.h> int main(void) { int x = -1; errno = 0; float y = sqrt(x); if (errno != 0) { perror("sqrt error"); exit(EXIT_FAILURE); } }上面示例中,求-1的平方根,导致报错。头文件errno.h提供宏errno,只要上一步操作出错,这个宏就会设置成非零值。perror()用来在报错信息前,加上sqrt error的自定义字符串。执行上面的程序,就会得到下面的报错信息。$ gcc test.c -lm $ ./a.out sqrt error: Numerical argument out of domain可变参数操作函数(1)输出函数下面是printf()的变体函数,用于按照给定格式,输出函数的可变参数列表(va_list)。vprintf():按照给定格式,输出到控制台,默认是显示器。vfprintf():按照给定格式,输出到文件。vsprintf():按照给定格式,输出到字符串。vsnprintf():按照给定格式,输出到字符串的安全版本。它们的原型如下,基本与对应的printf()系列函数一致,除了最后一个参数是可变参数对象。#include <stdio.h> #include <stdarg.h> int vprintf( const char * restrict format, va_list arg ); int vfprintf( FILE * restrict stream, const char * restrict format, va_list arg ); int vsprintf( char * restrict s, const char * restrict format, va_list arg ); int vsnprintf( char * restrict s, size_t n, const char * restrict format, va_list arg );它们的返回值都为输出的字符数,如果出错,返回负值。vsprintf()和vsnprintf()的第一个参数可以为 NULL,用来查看多少个字符会被写入。下面是一个例子。int logger(char *format, ...) { va_list va; va_start(va, format); int result = vprintf(format, va); va_end(va); printf("\n"); return result; } // 输出 x = 12 and y = 3.20 logger("x = %d and y = %.2f", x, y);(2)输入函数下面是scanf()的变体函数,用于按照给定格式,输入可变参数列表 (va_list)。vscanf():按照给定格式,从控制台读取(默认为键盘)。vfscanf():按照给定格式,从文件读取。vsscanf():按照给定格式,从字符串读取。它们的原型如下,跟对应的scanf()函数基本一致,除了最后一个参数是可变参数对象。#include <stdio.h> #include <stdarg.h> int vscanf( const char * restrict format, va_list arg ); int vfscanf( FILE * restrict stream, const char * restrict format, va_list arg ); int vsscanf( const char * restrict s, const char * restrict format, va_list arg );它们返回成功读取的项数,遇到文件结尾或错误,则返回 EOF。下面是一个例子。int error_check_scanf(int expected_count, char *format, ...) { va_list va; va_start(va, format); int count = vscanf(format, va); va_end(va); assert(count == expected_count); return count; } error_check_scanf(3, "%d, %d/%f", &a, &b, &c);
2023年09月20日
4 阅读
0 评论
0 点赞
1
2
3
...
14