后浪笔记一零二四

C程序设计语言-附录B标准库

附录B 标准库

本附录总结了ANSI标准定义的函数库。标准库不是C语言本身的构成部分,但是支持标准C 的实现会提供该函数库中的函数声明、类型以及宏定义。在这部分内容中,我们省略了一些使用比较受限的函数以及一些可以通过其他函数简单合成的函数,也省略了多字节字符的内容,同时,也不准备讨论与区域相关的一些属性,也就是与本地语言、国籍或文化相关的属性。

标准库中的函数、类型以及宏分别在下面的标准头文件中定义:

<assert.h>   <float.h>     <math.h>      <stdarg.h>    <stdlib.h>
<ctype.h>    <limits.h>    <setjmp.h>    <stddef.h>    <string.h>
<errno.h>    <locale.h>    <signal.h>    <stdio.h>     <time.h>

可以通过下述方式访问头文件:

#include <头文件>

头文件的包含顺序是任意的,并可包含任意多次。头文件必须被包含在任何外部声明或定义之外,并且,必须在使用头文件中的任何声明之前包含头文件。头文件不一定是一个源文件。

以下划线开头的外部标识符保留给标准库使用,同时,其他所有以一个下划线和一个大写字母开头的标识符以及以两个下划线开头的标识符也都保留给标准库使用。

B.1 输入与输出: <stdio.h>

头文件<stdio.h>中定义的输入和输出函数、类型以及宏的数目几乎占整个标准库的三分之一。

流(stream)是与磁盘或其他外围设备关联的数据的源或目的地。尽管在某些系统中(如在著名的UNIX系统中),文本流和二进制流是相同的,但标准库仍然提供了这两种类型的流。文本流是由文本行组成的序列,每一行包含0个或多个字符,并以'\n'结尾。在某些环境中,可能需要将文本流转换为其他表达形式(例如把'\n'映射成回车符和换行符),或从其他表示形式转换为文本流。二进制流是由未经处理的字节构成的序列,这些字节记录着内部数据,并具有下列性质:如果在同一系统中写入二进制流,然后再读取该二进制流,则读出和写入的内容完全相同。

打开一个流,将把该流与一个文件或设备连接起来,关闭流将断开这种连接。打开一个文件将返回一个指向FILE类型对象的指针,该指针记录了控制该流的所有必要信息。在不引起歧义的情况下,我们在下文中将不再区分“文件指针”和“流”。

程序开始执行时,stdin、stdout和stderr这3个流已经处于打开状态。

B.1.1 文件操作

下列函数用于处理与文件相关的操作。其中,类型size_t是由运算符sizeof生成的无符号整型。

FILE *fopen(const char *filename, const char *mode)

fopen函数打开filename指定的文件,并返回一个与之相关联的流。如果打开操作失败,则返回NULL。

访问模式mode可以为下列合法值之一:

"r"       打开文本文件用于读
"w"       创建文本文件用于写,并删除已存在的内容(如果有的话)
"a"       追加;打开或创建文本文件,并向文件末尾追加内容
"r+"      打开文本文件用于更新(即读和写)
"w+"      创建文本文件用于更新,并删除已存在的内容(如果有的话)
"a+"      追加;打开或创建文本文件用于更新,写文件时追加到文件末尾

用3种方式(更新方式)允许对同一文件进行读和写。在读和写的交叉过程中,必须调用fflush函数或文件定位函数。如果在上述访问模式之后再加上b,如"rb"或"w+b"等,则表示对二进制文件进行操作。文件名filename限定最多为FILENAME_MAX个字符。一次最多可打开FOPEN_MAX个文件。

1
2
FILE *freopen(const char *filename, const char *mode,
                    FILE *stream)

freopen函数以mode指定的模式打开filename指定的文件,并将该文件关联到stream指定的流。它返回stream;若出错则返回NULL。freopen函数一般用于改变与stdin、stdout和stderr相关联的文件。

int fflush(FILE *stream)

对输出流来说,fflush函数将已写到缓冲区但尚未写入文件的所有数据写到文件中。对输入流来说,其结果是未定义的。如果在写的过程中发生错误,则返回EOF,否则返回0。fflush(NULL)将清洗所有的输出流。

int fclose(FILE *stream);

fclose函数将所有未写入的数据写入stream流中,丢弃缓冲区中的所有未读输入数据,并释放自动分配的全部缓冲区,最后关闭流。若出错则返回EOF,否则返回0。

int remove(const char *filename)

remove函数删除filename指定的文件,这样,后续试图打开该文件的操作将失败。如果删除操作失败,则返回一个非0值。

int rename(const char *oldname, const char *newname)

rename函数修改文件的名字。如果操作失败,则返回一个非0的值。

FILE *tmpfile(void)

tmpfile函数以模式"wb+“创建一个临时文件,该文件在被关闭或程序正常结束时将被自动删除。如果创建操作成功,该函数返回一个流;如果创建文件失败,则返回NULL。

char *tmpnam(char s[L_tmpnam])

tmpnam(NULL)函数创建一个与现有文件名不同的字符串,并返回一个指向一内部静态数组的指针。tmpnam(s)函数把创建的字符串保存到数组s中,并将它作为函数值返回。s中至少要有L_tmpnam个字符的空间。tmpnam函数在每次被调用时均生成不同的名字。在程序执行的过程中,最多只能确保生成TMP_MAX个不同的名字。注意,tmpnam函数只是用于创建一个名字,而不是创建一个文件。

int setvbuf(FILE *stream, char *buf, int mode, size_t size)

setvbuf函数控制流stream的缓冲。在执行读、写以及其他任何操作之前必须调用此函数。当mode的值为_IOFBF时,将进行完全缓冲。当mode的值为_IOLBF时,将对文本文件进行行缓冲,当 mode的值为_IONBF时,表示不设置缓冲。如果buf的值不是NULL,则setvbuf函数将buf指向的区域作为流的缓冲区,否则将分配一个缓冲区。size决定缓冲区的长度。如果setvbuf函数出错,则返回一个非0的值。

void setbuf(FILE *stream, char *buf)

如果buf的值为NULL,则关闭流stream的缓冲;否则setbuf函数等价于(void) setvbuf(stream,buf,_IOFBF,BUFSIZ)

B.1.2 格式化输出

printf函数提供格式化输出转换。

int fprintf(FILE *stream, const char *format, ...)

fprintf函数按照format说明的格式对输出进行转换,并写到stream流中。返回值是实际写入的字符数。若出错则返回一个负值。

格式串由两种类型的对象组成:普通字符(将被复制到输出流中)与转换说明(分别决定下一后续参数的转换和打印)。每个转换说明均以字符%开头,以转换字符结束。在%与转换字符之间可以依次包含下列内容:

  • 标志(可以以任意顺序出现),用于修改转换说明

    • - 指定被转换的参数在其字段内左对齐
    • + 指定在输出的数前面加上正负号
    • 空格 如果第一个字符不是正负号,则在其前面加上一个空格
    • 0 对于数值转换,当输出长度小于字段宽度时,添加前导0进行填充
    • # 指定另一种输出形式。如果为o转换,则第一个数字为零;如果为x或X转换,则指定在输出的非0值前加0x或0X;对于e、E、f、g或G转换,指定输出总包括一个小数点;对于g或G转换,指定输出值尾部无意义的0将被保留
  • 一个数值,用于指定最小字段宽度。转换后的参数输出宽度至少要达到这个数值。如果参数的字符数小于此数值,则在参数左边(如果要求左对齐的话则为右边)填充一些字符。填充字符通常为空格,但是,如果设置了0填充标志,则填充字符为0。

  • 点号,用于分割字段宽度和精度。

  • 表示精度的数。对于字符串,它指定打印的字符的最大个数;对于e、E或f转换,它指定打印的小数点后的数字位数;对于g或G转换,它指定打印的有效数字位数;对于整型数,它指定打印的数字位数(必要时可加填充位0以达到要求的宽度)。

  • 长度修饰符h、l或L。h表示将相应的参数按short或unsigned short类型输出。l表示将相应的参数按long或unsigned long 类型输出;“L”表示将相应的参数按long double类型输出。

宽度和精度中的任何一个或两者都可以用*指定,这种情况下,该值将通过转换下一个参数计算得到(下一个参数必须为int类型)。

表B-1中列出了这些转换字符及其意义。如果%后面的字符不是转换字符,则其行为没有定义。

表B-1 printf函数的转换字符

转换字符 参数类型: 转换结果
d, i int; 有符号十进制表示
o unsigned int; 无符号八进制表示(无前导0)
x,X unsigned int; 无符号十六进制表示(无前导0x或0X)。如果是0x,则使用abcdef,如果是0X,则使用ABCDEF
u int; 无符号十进制表示
c int; 转换为unsigned char类型后为一个字符
s char *; 打印字符串中的字符,直到遇到'\0'或者已打印了由精度指定的字符数
f double; 形式为[-]mmm.ddd的十进制表示,其中,d的数目由精度确定,默认精度为6。精度为0时不输出小数点
e,E double; 形式为[-]m.dddddd e±xx或[-]m.dddddd E±xx的十进制表示。d的数目由精度确定,默认精度为6。精度为0时不输出小数点
g,G double; 当指数小于-4或大于等于精度时,采用%e或%E的格式,否则采用%f的格式。尾部的0与小数点不打印
p void *; 打印指针值(具体表示方式与实现有关)
n int *; 到目前为止,此printf调用输出的字符的数目将被写入到相应参数中。不进行参数转换
% 不进行参数转换;打印一个符号%

int printf(const char *format, ...)

printf(...)函数等价于fprintf(stdout, ...)

int sprintf(char *s, const char *format, ...)

sprintf函数与printf函数基本相同,但其输出将被写入到字符串s中,并以'\0'结束。s必须足够大,以足够容纳下输出结果。该函数返回实际输出的字符数,不包括'\0'

1
2
3
int vprintf(const char *format, va_list arg)
int vfprintf(FILE *stream, const char *format, va_list arg)
int vsprintf(char *s, const char *format, va_list arg)

vprintf、vfprintf、vsprintf这3个函数分别与对应的printf函数等价,但它们用arg代替了可变参数表。arg由宏va_start初始化,也可能由va_arg调用初始化。详细信息参见B.7节中对<stdarg.h>头文件的讨论。

B.1.3 格式化输入

scanf函数处理格式化输入转换。

int fscanf(FILE *stream, const char *format, ...)

fscanf函数根据格式串format从流stream中读取输入,并把转换后的值赋值给后续各个参数,其中的每个参数都必须是一个指针。当格式串format用完时,函数返回。如果到达文件的末尾或在转换输入前出错,该函数返回EOF;否则,返回实际被转换并赋值的输入项的数目。

格式串format通常包括转换说明,它用于指导对输入进行解释。格式字符串中可以包含下列项目:

  • 空格或制表符
  • 普通字符(%除外),它将与输入流中下一个非空白字符进行匹配
  • 转换说明,由一个%、一个赋值屏蔽字符*(可选)、一个指定最大字段宽度的数(可选)、一个指定目标字段宽度的字符(h、l或L)(可选)以及一个转换字符组成。

转换说明决定了下一个输入字段的转换方式。通常结果将被保存在由对应参数指向的变量中。但是,如果转换说明中包含赋值屏蔽字符*,例如%*s,则将跳过对应的输入字段,并不进行赋值。输入字段是一个由非空白符字符组成的字符串,当遇到下一个空白符或达到最大字段宽度(如果有的话)时,对当前输入字段的读取结束。这意味着,scanf函数可以跨越行的边界读取输入,因为换行符也是空白符(空白符包括空格、横向制表符、纵向制表符、换行符、回车符和换页符)。

转换字符说明了对输入字段的解释方式。对应的参数必须是指针。合法的转换字符如表B-2所示。

如果参数是指向short类型而非int类型的指针,则在转换字符d、i、n、o、u和x之前可以加上前缀h。如果参数是指向long类型的指针,则在这几个转换字符前可以加上字母l。如果参数是指向double类型而非float类型的指针,则在转换字符e、f和g前可以加上字符l。如果参数是指向long double类型的指针,则在转换字符e、f和g前可以加上字母L。

表B-2 Scanf函数的转换字符

转换字符 输入数据; 参数类型
d 十进制整型数; int *
i 整型数; int*。该整型数可以是八进制数(以0打头)或十六进制数(以0x或0X打头)
o 八进制整型数(可以带或不带前导0); int *
u 无符号十进制整型数; unsigned int *
x 十六进制整型数(可以带或不带前导0x或0X); int *
c 字符; char*,按照字段宽度的大小把读取的字符保存到指定的数组中,不增加字符'\0',字段宽度的默认值为1。在这种情况下,读取输入时将不跳过空白符。如果要读取下一个非空白符字符,可以使用%1s
s 由非空白符组成的字符串(不包含引号); char*。它指向一个字符数组,该字符数组必须有足够空间,以保存该字符串以及在尾部添加的'\0'字符
e、f、g 浮点数; float*。float类型浮点数的输入格式为: 一个可选的正负号、一个可能包含小数点的数字串、一个可选的指数字段(字母e或E后跟一个可能带正负号的整型数)
p printf("%p")函数调用打印的指针值; void*
n 将到目前为止该函数调用读取的字符数写入对应的参数中; int *。不读取输入字符。不增加已转换的项目计数
[...] 与方括号中的字符集合匹配的输入字符中最长的非空字符串;char*。末尾将添加字符'\0'[]...]表示集合中包含字符“]”
[^...] 与方括号中的字符集合不匹配的输入字符中最长的非空字符串;char*。末尾将添加字符'\0'[^]...]表示集合中不包含字符“]”
% 表示“%”,不进行赋值

int scanf(const char *format, ...)

scanf(…)函数与fscanf(stdin, …)相同。

int sscanf(const char *s, const char *format, ...)

sscanf(s, …)函数与scanf(…)等价,所不同的是,前者的输入字符来源于字符串s。

B.1.4 字符输入/输出函数

int fgetc(FILE *stream)

fgetc函数返回stream流的下一个字符,返回类型unsigned char (被转换为int类型)。如果到达文件末尾或发生错误,则返回EOF。

char *fgets(char *s, int n, FILE *stream)

fgets函数最多将下n-1个字符读入到数组s中。当遇到换行符时,把换行符读入到数组s中,读取过程终止。数组s以'\0'结尾。fgets函数返回数组s。如果到达文件的末尾或发生错误,则返回NULL。

int fputc(int c, FILE *stream)

fputc函数把字符c(转换为unsigned char类型)输出到流stream中。它返回写入的字符,若出错则返回EOF。

int fputs(const char *s, FILE *stream)

fputs函数把字符串s(不包含字符'\n')输出到流stream中;它返回一个非负值,若出错则返回EOF。

int getc(FILE *stream)

getc函数等价于fgetc,所不同的是,当getc函数定义为宏时,它可能多次计算stream的值。

int getchar(void)

getchar函数等价于getc(stdin)

char *gets(char *s)

gets函数把下一个输入行读入到数组s中,并把末尾的换行符替换为字符'\0'。它返回数组s,如果到达文件的末尾或发生错误,则返回NULL。

int putc(int c, FILE *stream)

putc函数等价于fputc,所不同的是,当putc函数定义为宏时,它可能多次计算stream的值。

int putchar(int c)

putchar(c)函数等价于putc(c,stdout)

int puts(const char *s)

puts函数把字符串s和一个换行符输出到stdout中。如果发生错误,则返回EOF;否则返回一个非负值。

int ungetc(int c, FILE *stream)

ungetc函数把c(转换为unsigned char类型)写回到流stream中,下次对该流进行读操作时,将返回该字符。对每个流只能写回一个字符,且此字符不能是EOF。ungetc函数返回被写回的字符;如果发生错误,则返回EOF。

B.1.5 直接输入/输出函数

size_t fread(void *ptr, size_t size, size_t nobj, FILE *stream)

fread函数从流stream中读取最多nobj个长度为size的对象,并保存到ptr指向的数组中。它返回读取的对象数目,此返回值可能小于nobj。必须通过函数feof和ferror获得结果执行状态。

1
2
size_t fwrite(const void *ptr, size_t size, size_t nobj,
                        FILE *stream)

fwrite函数从ptr指向的数组中读取nobj个长度为size的对象,并输出到流stream中。它返回输出的对象数目。如果发生错误,返回值会小于nobj的值。

B.1.6 文件定位函数

int fseek(FILE *stream, long offset, int origin)

fseek函数设置流stream的文件位置,后续的读写操作将从新位置开始。对于二进制文件,此位置被设置为从origin开始的第offset个字符处。origin的值可以为SEEK_SET(文件开始处)、SEEK_CUR(当前位置)或SEEK_END(文件结束处)。对于文本流,offset必须设置为0,或者是由函数ftell返回的值(此时origin的值必须是SEEK_SET)。fseek函数在出错时返回一个非0值。

long ftell(FILE *stream)

ftell函数返回stream流的当前文件位置。出错时该函数返回-1L。

void rewind(FILE *stream)

rewind(fp)函数等价于语句fseek(fp,0L,SEEK_SET);clearerr(fp)的执行结果。

int fgetpos(FILE *stream, fpos_t *ptr)

fgetpos函数把stream流的当前位置记录在*ptr中,供随后的fsetpos函数调用使用。若出错则返回一个非0值。

int fsetpos(FILE *stream, const fpos_t *ptr)

fsetpos函数将流stream的当前位置设置为fgetpos记录在*ptr中的位置。若出错则返回一个非0值。

B.1.7 错误处理函数

当发生错误或到达文件末尾时,标准库中的许多函数都会设置状态指示符。这些状态指示符可被显式地设置和测试。另外,整型表达式errno(在<errno.h>中声明)可以包含一个错误编号,据此可以进一步了解最近一次出错的信息。

void clearerr(FILE *stream)

clearerr函数清除与流stream相关的文件结束符和错误指示符。

int feof(FILE *stream)

如果设置了与stream流相关的文件结束指示符,feof函数将返回一个非0值。

int ferror(FILE *stream)

如果设置了与stream流相关的错误指示符,ferror函数将返回一个非0值。

void perror(const char *s)

perror(s)函数打印字符串s以及与errno中整型值相应的错误信息,错误信息的具体内容与具体的实现有关。该函数的功能类似于执行下列语句:

fprintf(stderr, "%s: %s\n", s, "error message")

有关函数strerror的信息,参见B.3节中的介绍。

B.2 字符类别测试:<ctype.h>

头文件<ctype.h>中声明了一些测试字符的函数。每个函数的参数均为int类型,参数的值必须是EOF或可用unsigned char类型表示的字符,函数的返回值为int类型。如果参数c满足指定的条件,则函数返回非0值(表示真),否则返回0(表示假)。这些函数包括:

isalnum(c)    函数isalpha(c)或isdigit(c)为真
isalpha(c)    函数isupper(c)或islower(c)为真
iscntrl(c)    c为控制字符
isdigit(c)    c为十进制数字
isgraph(c)    c是除空格外的可打印字符
islower(c)    c是小写字母
isprint(c)    c是包括空格的可打印字符
ispunct(c)    c是除空格、字母和数字外的可打印字符
isspace(c)    c是空格、换页符、换行符、回车符、横向制表符或纵向制表符
isupper(c)    c是大写字母
isxdigit(c)   c是十六进制数字

在7位ASCII字符集中,可打印字符是从0x20(' ')到0x7E('~')之间的字符;控制字符是从0(NUL)到0x1F(US)之间的字符以及字符0x7F(DEL)。

另外,下面两个函数可用于字母的大小写转换:

1
2
int tolower(int c)    c转换为小写字母
int toupper(int c)    c转换为大写字母

如果c是大写字母,则tolower(c)返回相应的小写字母,否则返回c。如果c是小写字母,则toupper(c)返回相应的大写字母,否则返回c。

B.3 字符串函数:<string.h>

头文件<string.h>中定义了两组字符串函数。第一组函数的名字以str开头;第二组函数的名字以mem开头。除函数memmove外,其他函数都没有定义重叠对象间的复制行为。比较函数将把参数作为unsigned char类型的数组看待。

在下表中,变量s和t的类型为char *; cs和ct的类型为const char *; n的类型为size_t; c的类型为int(将被转换为char类型)。

char *strcpy(s,ct)        将字符串ct(包括'\0')复制到字符串s中,并返回s

char *strncpy(s,ct,n)     将字符串ct中最多n个字符复制到字符串s中,并返回s。如果ct中少于n个字符,则用'\0'填充

char *strcat(s,ct)        将字符串ct连接到s的尾部,并返回s

char *strncat(s,ct,n)     将字符串ct中最多前n个字符连接到字符串s的尾部,并以'\0'结束;该函数返回s

int strcmp(cs,ct)         比较字符串cs和ct;当cs<ct时,返回一个负数;当cs==ct时,返回0;当cs>ct时,返回0

int strncmp(cs,ct,n)      将字符串cs中至多前n个字符与字符串ct相比较。当cs<ct时,返回一个负数;当cs==ct时,返回0;当cs>ct时,返回0

char *strchr(cs,c)        返回指向字符c在字符串cs中第一次出现的位置的指针;如果cs中不包含c,则该函数返回NULL

char *strrchr(cs,c)       返回指向字符c在字符串cs中最后一次出现的位置的指针;如果cs中不包含c,则该函数返回NULL

size_t strspn(cs,ct)      返回字符串cs中包含ct中的字符的前缀的长度

size_t strcspn(cs,ct)     返回字符串cs中不包含ct中的字符的前缀的长度

char *strpbrk(cs,ct)      返回一个指针,它指向字符串ct中的任意字符第一次出现在字符串cs中的位置;如果cs中没有与ct相同的字符,则返回NULL

char *strstr(cs,ct)       返回一个指针,它指向字符串ct第一个出现在字符串cs中的位置;如果cs中不包含字符串ct,则返回NULL

size_t strlen(cs)         返回字符串cs的长度

char *strerror(n)         返回一个指针,它指向与错误编号n对应的错误信息字符串(错误信息的具体内容与具体实现相关)

char *strtok(s,ct)        strtok函数在s中搜索由ct中的字符界定的记号。详细信息参见下面的讨论

对strtok(s,ct)进行一系列调用,可以把字符串s分成许多记号,这些记号以ct中的字符为分界符。第一次调用时,s为非空。它搜索s,找到不包含ct中字符的第一个记号,将s中的下一个字符替换为'\0',并返回指向记号的指针。随后,每次调用strtok函数时(由s的值是否为NULL指示),均返回下一个不包含ct中字符的记号。当s中没有这样的记号时,返回NULL。每次调用时字符串ct可以不同。

以mem开头的函数按照字符数组的方式操作对象,其主要目的是提供一个高效的函数接口。在下表列出的函数中,s和t类型均为void *,cs和ct的类型均为const void *,n的类型为size_t,c的类型为int(将被转换为unsigned char类型)。

1
2
3
4
5
void *memcpy(s,ct,n)      将字符串ct中的n个字符拷贝到s中,并返回s
void *memmove(s,ct,n)     该函数的功能与memcpy相似,所不同的是,当对象重叠时,该函数仍能正确执行
int memcmp(cs,ct,n)       cs的前n个字符与ct进行比较,其返回值与strcmp的返回值相同
void *memchr(cs,c,n)      返回一个指针,它指向c在cs中第一次出现的位置。如果在cs的前n个字符中找不到匹配,则返回NULL
void *memset(s,c,n)       s中的前n个字符替换为c,并返回s

B.4 数学函数:<math.h>

头文件<math.h>中声明了一些数学函数和宏。

宏EDOM和ERANGE(在头文件<error.h>中声明)是两个非0整型常量,用于指示函数的定义域错误和值域错误;HUGE_VAL是一个double类型的正数。当参数位于函数定义的作用域之外时,就会出现定义域错误。在发生定义域错误时,全局变量errno的值将被设置为EDOM,函数的返回值与具体的实现有关。如果函数的结果不能用double类型表示,则会发生值域错误。当结果上溢时,函数返回HUGE_VAL,并带有正确的正负号,errpo的值将被设置为ERANGE。当结果下溢时,函数返回0,而errno是否设置为ERANGE要视具体的实现而定。

在下表中,x和y的类型为double,n的类型为int,所有函数的返回值的类型均为double。三角函数的角度用弧度表示。

sin(x)                x的正弦值
cos(x)                x的余弦值
tan(x)                x的正切值
asin(x)               sin^(-1)(x),值域为[-π/2,π/2],其中x∈[-1,1]
acos(x)               cos^(-1)(x),值域为[0,π],其中x∈[-1,1]
atan(x)               tan^(-1)(x),值域为[-π/2,π/2]
atan2(y,x)            tan^(-1)(y/x),值域为[-π,π]
sinh(x)               x的双曲正弦值
cosh(x)               x的双曲余弦值
tanh(x)               x的双曲正切值
exp(x)                幂函数e^x
log(x)                自然对数ln(x),其中x>0
log10(x)              以10为底的对数log_(10)(x),其中x>0
pow(x,y)              x^y。如果x=0且y≤0,或者x<0且y不是整型数,将产生定义域错误
sqrt(x)               x的平方根,其中x≥0
ceil(x)               不小于x的最小整型数,其中x的类型为double
floor(x)              不大于x的最大整型数,其中x的类型为double
fabs(x)               x的绝对值|x|
ldexp(x,n)            计算x·(2^n)的值
frexp(x,int *exp)     把x分成一个在[1/2,1]区间内的真分数和一个2的幂数。结果将返回真分数部分,并将幂数保存在`*exp`中。如果x为0,则这两部分均为0
modf(x,double *ip)    把x分成整数和小数部分,两部分的正负号均与x相同。该函数返回小数部分,整数部分保存在`*ip`中
fmod(x,y)             求x/y的浮点余数,符号与x相同。如果y为0,则结果与具体的实现相关

B.5 实用函数:<stdlib.h>

头文件<stdlib.h>中声明了一些执行数值转换、内存分配以及其他类似工作的函数。

double atof(const char *s)

atof函数将字符串s转换为double类型。该函数等价于strtod(s,(char**)NULL)

int atoi(const char *s)

atoi函数将字符串s转换为int类型。该函数等价于(int)strtol(s,(char**)NULL,10)

long atol(const char *s)

atol函数将字符串s转换为long类型。该函数等价于strtol(s,(char**)NULL,10)

double strtod(const char *s, char **endp)

strtod函数将字符串s的前缀转换为double类型,并在转换时跳过s的前导空白符。除非endp为NULL,否则该函数将把指向s中未转换部分(s的后缀部分)的指针保存在*endp中。如果结果上溢,则函数返回带有适当符号的HUGE_VAL;如果结果下溢,则返回0。在这两种情况下,errno都将被设置为ERANGE。

long strtol(const char *s, char **endp, int base)

strtol函数将字符串s的前缀转换为long类型,并在转换时跳过s的前导空白符。除非endp为NULL,否则该函数将把指向s中未转换部分(s的后缀部分)的指针保存在*endp中。如果base的取值在2~36之间,则假定输入是以该数为基底的;如果base的取值为0,则基底为八进制、十进制或十六进制。以0位前缀的是八进制,以0x或0X为前缀的是十六进制。无论在哪种情况下,字母均表示10~base-1之间的数字。如果base值是16,则可以加上前导0x或0X。如果结果上溢,则函数根据结果的符号返回LONG_MAXLONG_MIN,同时将errono的值设置为ERANGE。

unsigned long strtoul(const char *s, char **endp, int base)

strtoul函数的功能与strtol函数相同,但其结果为unsigned long类型,错误值为ULONG_MAX

int rand(void)

rand函数产生一个0~RAND_MAX之间的伪随机整数。RAND_MAX的取值至少为32767。

void srand(unsigned int seed)

srand函数将seed作为生成新的伪随机数序列的种子数。种子数seek的初值为1。

void *calloc(size_t nobj, size_t size)

calloc函数为由nobj个长度为size的对象组成的数组分配内存,并返回指向分配区域的指针;若无法满足要求,则返回NULL。该空间的初始长度为0字节。

void *malloc(size_t size)

malloc函数为长度为size的对象分配内存,并返回指向分配区域的指针;若无法满足要求,则返回NULL。该函数不对分配的内存区域进行初始化。

void *realloc(void *p, size_t size)

realloc函数将p指向的对象的长度修改为size个字节。如果新分配的内存比原内存大,则原内存的内容保持不变,增加的空间不进行初始化。如果新分配的内存比原内存小,则新分配内存单元不被初始化。realloc函数返回指向新分配空间的指针;若无法满足要求,则返回NULL,在这种情况下,原指针p指向的单元内容保持不变。

void free(void *p)

free函数释放p指向的内存空间。当p的值为NULL时,该函数不执行任何操作。p必须指向先前使用动态分配函数malloc、realloc或calloc分配的空间。

void abort(void)

abort函数使程序非正常终止。其功能与raise(SIGABRT)类似。

void exit(int status)

exit函数使程序正常终止。atexit函数的调用顺序与登记的顺序相反,这种情况下,所有已打开的文件缓冲区将被清洗,所有已打开的流将被关闭,控制也将返回给环境。status的值如何返回给环境要视具体的实现而定,但0值表示终止成功。也可使用值EXIT_SUCCESSEXIT_FAILURE作为返回值。

int atexit(void (*fcn)(void))

atexit函数登记函数fcn,该函数将在程序正常终止时被调用。如果登记失败,则返回非0值。

int system(const char *s)

system函数将字符串s传递给执行环境。如果s的值为NULL,并且有命令处理程序,则该函数返回非0值。如果s的值不是NULL,则返回值与具体的实现有关。

char *getenv(const char *name)

getenv函数返回与name有关的环境字符串。如果该字符串不存在,则返回NULL。其细节与具体的实现有关。

1
2
3
void *bsearch(const void *key, const void *base,
    size_t n, size_t size,
    int (*cmp)(const void *keyval, const void *datum))

bsearch函数在base[0]…base[n-1]之间查找与*key匹配的项。在函数cmp中,如果第一个参数(查找关键字)小于第二个参数(表项),它必须返回一个负值;如果第一个参数等于第二个参数,它必须返回零;如果第一个参数大于第二个参数,它必须返回一个正值。数组base中的项必须按升序排序。bsearch函数返回一个指针,它指向一个匹配项,如果不存在匹配项,则返回NULL。

1
2
void qsort(void *base, size_t n, size_t size,
            int (*cmp)(const void *, const void *))

qsort函数对base[0]…base[n-1]数组中的对象进行升序排序,数组中每个对象的长度为size。比较函数cmp与bsearch函数中的描述相同。

int abs(int n)

abs函数返回int类型参数n的绝对值。

long labs(long n)

labs函数返回long类型参数n的绝对值。

div_t div(int num, int denom)

div函数计算num/denom的商与余数,并把结果分别保存在结构类型div_t的两个int类型的成员quot和rem中。

ldiv_t ldiv(long num, long denom)

ldiv函数计算num/denom的商和余数,并把结果分别保存在结构类型ldiv_t的两个long类型的成员quot和rem中。

B.6 诊断:<assert.h>

assert宏用于为程序增加诊断功能。其形式如下:

void assert(int 表达式)

如果执行语句

assert (表达式)

时,表达式的值为0,则assert宏将在stderr中打印一条消息,比如:

Assertion failed: 表达式, file源文件名, line行号

打印消息后,该宏将调用abort终止程序的执行。其中的源文件名和行号来自于预处理器宏__FILE____LINE__

如果定义了宏NDEBUG,同时又包含了头文件<assert.h>,则assert宏将被忽略。

B.7 可变参数表: <stdarg.h>

头文件<stdarg.h>提供了遍历未知数目和类型的函数参数表的功能。

假定函数f带有可变数目的实际参数,lastarg是它的最后一个命名的形式参数。那么,在函数f内声明一个类型为va_list的变量ap,它将依次指向每个实际参数。

va_list ap;

在访问任何未命名的参数前,必须用va_start宏初始化ap一次:

va_start(va_list ap, lastarg);

此后,每次执行宏va_arg都将产生一个与下一个未命名的参数具有相同类型和数值的值,它同时还修复ap,以使得下一次执行va_arg时返回下一个参数:

类型 va_arg(va_list ap,类型);

在所有的参数处理完毕之后,且在退出函数f之前,必须调用宏va_end一次,如下所示:

void va_end(va_list ap);

B.8 非局部跳转:<setjmp.h>

头文件<setjmp.h>中的声明提供了一种不同于通常的函数调用和返回顺序的方式,特别是,它允许立即从一个深层嵌套的函数调用中返回。

int setjmp(jmp_buf env)

setjmp宏将状态信息保存到env中,供longjmp使用。如果直接调用setjmp,则返回值为0;如果是在longjmp中调用setjmp,则返回值为非0。setjmp只能用于某些上下文中,如用于if语句、switch语句、循环语句的条件测试中以及一些简单的关系表达式中。例如:

1
2
3
4
if (setjmp(env) == 0)
    /* 直接调用setjmp时,转移到这里 */
else
    /* 调用longjmp时,转移到这里 */

void longjmp(jmp_buf env, int val)

longjmp通过最近一次调用setjmp时保存到env中的信息恢复状态,同时,程序重新恢复执行,其状态等同于setjmp宏调用刚刚执行完并返回非0值val。包含setjmp宏调用的函数的执行必须还没有终止。除下列情况外,可访问对象的值同调用longjmp时的值相同:在调用setjmp宏后,如果调用setjmp宏的函数中的非volatile自动变量改变了,则它们将变成未定义状态。

B.9 信号:<signal.h>

头文件<signal.h>提供了一些处理程序运行期间引起的各种异常条件的功能,比如来源于外部的中断信号或程序执行错误引起的中断信号。

void (*signal(int sig, void (*handler)(int)))(int)

signal决定了如何处理后续的信号。如果handler的值是SIG_DFL,则采用由实现定义的默认行为;如果handler的值是SIG_IGN,则忽略该信号;否则,调用handler指向的函数(以信号作为参数)。有效的信号包括:

SIGABRT    异常终止,例如由abort引起的终止
SIGFPE     算术运算出错,如除数为0或溢出
SIGILL     非法函数映像,如非法指令
SIGINT     用于交互式目的信号,如中断
SIGSEGV    非法存储器访问,如访问不存在的内存单元
SIGTERM    发送给程序的终止请求

对于特定的信号,signal将返回handler的前一个值;如果出现错误,则返回值SIG_ERR

当随后碰到信号sig时,该信号将恢复为默认行为,随后调用信号处理程序,就好像由(*handler)(sig)调用的一样。信号处理程序返回后,程序将从信号发生的位置重新开始执行。

信号的初始状态由具体的实现定义。

int raise(int sig)

raise向程序发送信号sig。如果发送不成功,则返回一个非0值。

B.10 日期与时间函数:<time.h>

头文件<time.h>中声明了一些处理日期与时间的类型和函数。其中的一些函数用于处理当地时间,因为时区等原因,当地时间与日历时间可能不相同。clock_ttime_t是两个表示时间的算术类型,struct tm用于保存日历时间的各个构成部分。结构tm中各成员的用途及取值范围如下所示:

int tm_sec;    从当前分钟开始经过的秒数(0,61)
int tn_min;    从当前小时开始经过的分钟数(0,59)
int tm_hour;   从午夜开始经过的小时数(0,23)
int tm_mday;   当月的天数(1,31)
int tm_mon;    从1月起经过的月数(0,11)
int tm_year;   从1900年起经过的年数
int tm_wday;   从星期天起经过的天数(0,6)
int tm_yday;   从1月1日起经过的天数(0,365)
int tm_isdst;  夏令时标记

使用夏令时,tm_isdst的值为正,否则为0。如果该信息无效,则其值为负。

clock_t clock(void)

clock函数返回程序开始执行后占用的处理器时间。如果无法获取处理器时间,则返回值为-1。close()/CLOCKS_PER_SEC是以秒为单位表示的时间。

time_t time(time_t *tp)

time函数返回当前日历时间。如果无法获取日历时间,则返回值为-1。如果tp不是NULL,则同时将返回值赋给*tp

double difftime(time_t time2, time_t time1)

difftime函数返回time2-time1的值(以秒为单元)。

time_t mktime(struct tm *tp)

mktime函数将结构*tp中的当地时间转换为与time表示方式相同的日历时间。结构中各成员的值位于上面所示范围之内。mktime函数返回转换后得到的日历时间;如果该时间不能表示,则返回-1。

下面4个函数返回指向可被其他调用覆盖的静态对象的指针。

char *asctime(const struct tm *tp)

asctime函数将结构*tp中的时间转换为下列所示的字符串形式:

Sun Jan 3 15:14:13 1988\n\0

char *ctime(const time_t *tp)

ctime函数将结构*tp中的日历时间转换为当地时间。它等价于下列函数调用:

asctime(localtime(tp))

struct tm *gmtime(const time_t *tp)

gmtime函数将*tp中的日历时间转换为协调世界时(UTC)。如果无法获取UTC,则该函数返回NULL。函数名字gmtime有一定的历史意义。

struct tm *localtime(const time_t *tp)

localtime函数将结构*tp中的日历时间转换为当地时间。

1
2
size_t strftime(char *s, size_t smax, const char *fmt,
                    const struct tm *tp)

strftime函数根据fmt中的格式把结构*tp中的日期与时间信息转换为指定的格式,并存储到s上,其中fmt类似于printf函数中的格式说明。普通字符(包括终结符'\0')将复制到s中。每个%c将按照下面描述的格式替换为与本地环境相适应的值。最多smax个字符写到s中。strftime函数返回实际写到s中的字符数(不包括字符’\0’);如果字符数多于smax,该函数将返回值0。

fmt的转换说明及其含义如下所示:

%a       一星期中各天的缩写名
%A       一星期中各天的全名
%b       缩写的月份名
%B       月份全名
%c       当地时间和日期表示
%d       一个月中的某一天(01-31)
%H       小时(24小时表示)(00~23)
%I       小时(12小时表示)(01~12)
%j       一年中的各天(001~366)
%m       月份(01~12)
%M       分钟(00~59)
%p       与AM与PM相应的当地时间等价表示方法
%S       秒(00-61)
%U       一年中的星期序号(00-53,将星期日看做是每周的第一天)
%w       一周中的各天(0-6,星期日为0)
%W       一年中的星期序号(00-53,将星期一看作是每周的第一天)
%x       当地日期表示
%X       当地时间表示
%y       不带世纪数目的年份(00-99)
%Y       带世纪数目的年份
%Z       时区名(如果有的话)
%%       %本身

B.11 与具体实现相关的限制:<limits.h>和<float.h>

头文件<limits.h>定义了一些表示整型大小的常量。以下所列的值是可接受的最小值在实际系统中可以使用更大的值。

CHAR_BIT                      8                 char类型的位数
CHAR_MAX   UCHAR_MAX或SCHAR_MAX                 char类型的最大值
CHAR_MIN           0或SCHAR_MIN                 char类型的最小值
INT_MAX                  +32767                 int类型的最大值
INT_MIN                  -32767                 int类型的最小值
LONG_MAX            +2147483647                 long类型的最大值
LONG_MIN            -2147483647                 long类型的最小值
SCHAR_MAX                  +127                 signed char类型的最大值
SCHAR_MIN                  -127                 signed char类型的最小值
SHRT_MAX                 +32767                 short类型的最大值
SHRT_MIN                 -32767                 short类型的最小值
UCHAR_MAX                   255                 unsigned char类型的最大值
UINT_MAX                  65535                 unsigned int类型的最大值
ULONG_MAX            4294967295                 unsigned long类型的最大值
USHRT_MAX                 65535                 unsigned short类型的最大值

下表列出的名字是<float.h>的一个子集,它们是与浮点算术运算相关的一些常量。给出的每个值代表相应量的最小取值。各个实现可以定义适当的值。

FLT_RADIX                2           指数表示的基数,例如2、16
FLT_ROUNDS                           加法的浮点舍入模式
FLT_DIG                  6           表示精度的十进制数字
FLT_EPSILON           1E-5           最小的数x,x满足:1.0 + x ≠ 1.0
FLT_MANT_DIG                         尾数中的数(以FLT_RADIX为基数)
FLT_MAX              1E+37           最大的浮点数
FLT_MAX_EXP                          最大的数n, n满足: FLT_RADIX^n-1仍是可表示的
FLT_MIN              1E-37           最小的规格化浮点数
FLT_MIN_EXP                          最小的数n,n满足:10^n是一个规格化数
DBL_DIG                 10           表示精度的十进制数字
DBL_EPSILON           1E-9           最小的数x,x满足:1.0 + x ≠ 1.0
DBL_MANT_DIG                         尾数中的数(以FLT_RADIX为基数)
DBL_MAX              1E+37           最大的双精度浮点数
DBL_MAX_EXP                          最大的数n,n满足:FLT_RADIX^n-1仍是可表示的
DBL_MIN              1E-37           最小的规格化双精度浮点数
DBL_MIN_EXP                          最小的数n, n满足:10^n是一个规格化数

专题:

本文发表于 2022-09-13,最后修改于 2022-09-13。

本站永久域名「 jiavvc.top 」,也可搜索「 后浪笔记一零二四 」找到我。


上一篇 « go-build 下一篇 » C程序设计语言-附录A参考手册

赞赏支持

请我吃鸡腿 =^_^=

i ysf

云闪付

i wechat

微信

推荐阅读

Big Image