简介
C 标准
国际标准化组织 ISO 是指定 C 标准的最高机构。
C 源文件和头文件的命名惯例:
C 标准库共有 15 个头文件(按首字母排序):
assert.h, ctype.h, errno.h, float.h, limits.h,
locale.h, math.h, setjmp.h, signal.h, stdarg.h,
stddef.h, stdio.h, stdlib.h, string.h, time.h
各头文件之间是相互独立的。
与 C++ 版本的区别
这些头文件在 C++ 的 STL 中都有对应的文件,且 C++ 版本中的内容常常会在 C 版本的基础上有所扩充,部分还会有所改变
如在 C 标准库的 stdlib.h 中只有 strtol, strtoul, strtof,但是在 cstdlib 中,有 strtof, strtod, strtold, strtol, strtoll, strtoul, strtoull。
在 C 标准库中 strtof 返回的是 double 类型,而在 cstdlib 中,strtof 返回 float 类型而 strtod 返回 double 类型。
assert.h 唯一的目的就是提供宏 assert 的定义。可以在程序中关键的地方使用这个宏来进行断言。
如果一个断言被证明非真,则希望使执行终止,并在标准错误流中输出适当信息。断言只在调试程序时有用。
内容
头文件 assert.h 定义了宏 assert,还引用了另一个宏 NDEBUG
头文件 ctype.h 声明了几个可以用于识别和转换字符的函数。
所有这些函数的参数和返回值都是 int 类型,但是可以传递 unsigned char 类型的实参。如:
bool a = isalnum('b');
注意:ctype.h 中的函数只能处理 ASCII 字符,即传递的实参必须在 0~127 之间或等于宏 EOF(在 stdio.h 中定义的) 的值。如果参数是其他值,则行为未定义。
字符判断函数
int isalnum(int c); //判别所有 isalpha 或 isdigit 为真的字符。
int isalpha(int c); //判别所有 isupper 或 islower 为真的字符。
int iscntrl(int c); //判别所有的控制字符。
int isdigit(int c); //判别所有的十进制数字字符,即 0~9。
int isgraph(int c); //判别除空格外的所有打印字符,即图形字符,输出到显式设备时可见的字符。
int islower(int c); //判别所有的小写字母。
int isprint(int c); //判别包括空格在内的所有打印字符。即空格和图形字符。
int ispunct(int c); //判别除了空格和 isalnum 判别为真的字符外的所有打印字符。即各类标点符号。
int isspace(int c); //判别所有标准的空白字符,包括:空格和 5 个控制字符:换页、换行、回车、水平制表符、垂直制表符。
int isupper(int c); //判别所有的大写字母。
int isdxigit(int c); //判别所有的十六进制数字字符。即 0~9 加上 A-F、a-f。
字符大小写转换函数
int tolower(int c);
int toupper(int c);
errno.h 定义了3个与错误状态的报告有段的宏:
EDOM 和 ERANGE //展开为具有非零值的整数常量表达式,适合在 #if 预处理指令中使用。
errno //展开为一个可以修改的 int 类型的左值
errno 的值在程序启动时为零,可以被某几个库函数设置为一个正的错误编号。
float.h 和 limits.h 中定义了几个可以展开为各种范围和参数的宏。
float.h 中的一些宏定义了浮点类型的最大值和最小值
limits.h 中的一些宏定义了整数类型的最大值和最小值
SCHAR_MIN, SCHAR_MAX //signed char 类型的最小值和最大值,即 -127 和 +127
UCHAR_MAX
CAHR_MIN, CHAR_MAX //char 类型的最小值和最大值
SHRT_MIN, SHRT_MAX //short int 类型的最小值和最大值,即 -32767 和 +32767
USHRT_MAX
INT_MIN, INT_MAX //int 类型的最小值和最大值,即 -32767 和 +32767
UINT_MAX
LONG_MIN, LONG_MAX //long 类型的最小值和最大值,即 -2147483647 和 +2147483767
ULONG_MAX
上面列的值是《C标准库》中说的值,其中 int 和 long 类型的最小值和最大值明显是 32 位机器中的值。
math.h 中声明了一些数学函数、定义了一个宏。
数学库中每个函数的参数值和返回值都是 double 类型的,具有 56 位的精度。
math.h 中的函数很少,cmath 则多很多,cmath 的许多内容都是 C++11 定义的,如四舍五入函数 round() 等。
内容
宏
HUGE_VAL
错误情况的处理
如果输入参数在函数的定义域外,会发生定义域错误,此时函数返回一个特定的值,errno 设置为宏 EDOM。
如果数学库中的函数计算结果无法用 double 表示,会发生值域错误,如果结果上溢,函数返回 HUGE_VAL 的值,errno 设置为宏 ERANGE;如果结果下溢,函数返回 0。
三角函数
double sin(double x); //参数 x 的单位是弧度
double cos(double x); //参数 x 的单位是弧度
double tan(double x); //参数 x 的单位是弧度
double asin(double x); //返回值范围为 [-pi/2, pi/2]
double acos(double x); //返回值范围为 [0,pi]
double atan(double x); //返回值范围为 [-pi/2, pi/2]
double atan2(double y, double x); //返回以坐标系中坐标为(x,y)的点的角度,范围 [-pi, pi]
double sinh(double x); //返回 x 的双曲正弦
double cosh(double x);
double tanh(double x);
指数函数和对数函数
double exp(double x); //返回 e 的 x 次幂的值
double log(double x); //返回 x 的自然对数
double log10(double x); //返回 x 的以 10 为底的对数
double frexp(double value, int *exp); //把 value 拆分为一个 [0.5, 1) 之间的规格化小数和 2 的整数幂,返回值是规格化小数 mantissa,指数存入 exp 中。 x = mantissa * 2^exp;
double ldexp(double x, int *exp); //计算 x 和 2 的 exp 次幂的乘积: x * 2^exp
double modf(double x, double *integer); //将 x 分为整数部分和小数部分,返回值为小数部分,并设置 integer 为整数部分
幂函数
double pow(double x, double y); //返回 x 的 y 次幂。如果 x<0 且 y不是整数,会发生定义语错误
double pow(double x, int y); //double 可以换成 float 或 long double,总之第一个参数必须是浮点数
double sqrt(double x); //计算 x 的非负平方根,如果 x<0,会发生定义域错误。double 可以换成 float 或 long double,总之必须是浮点数
取整函数、取余函数和绝对值
int ceil(double x); //返回大于等于 x 的最小整数
int floor(double x); //返回小于等于 x 的最大整数
double fabs(double x); //返回 x 的绝对值
double fmod(double x, double y);//返回 x 除以 y 的余数。整数取余直接用 %
setjump.h 中定义了一个类型 jum_buf,一个宏 setjmp,一个函数 longjump 用来实现非本地跳转。比如从一个函数跳转到另一个函数中。
jmp_buf //一个数组类型,存储恢复一个调用环境所需的信息。
int setjmp (jmp_buf env); // setjump 是一个宏,它将它的调用环境保存在参数 env 中。
void longjump(jmp_buf env, int val); //函数 longjmp 使用参数 env 来恢复程序的相同调用中 setjmp 的最近一次调用保存的环境。
信号是程序执行过程中发生的异常事件。程序不能屏蔽的信号要求立即得到处理,如果不指定处理方法,信号会被当做致命错误对待,导致程序终止。C 标准库会在程序终止前向标准错误流输出一条错误信息。
可以通过以下三种方式处理信号:
signal.h 用来处理信号。signal 中声明了一个类型 sig_atomic_t 和两个函数 raise、signal,定义几个宏。
类型
sig_atomic_t //一个整数类型。
宏
SIG_DFL //默认的信号处理程序
SIG_ERR //表示一个信号错误
SIG_IGN //忽略信号
"下面的宏是信号码"
SIGABRT //程序异常终止
SIGFPE //算术运算出错,如除 0 或溢出
SIGILL //非法函数映像,如非法指令。
SIGINT //中断信号,如 Ctrl+C
SIGSEGV //非法访问存储器,如访问不存在的内存单元
SIGTERM //发送给本程序的终止请求信号
函数
void ( *signal(int sig, void (*func)(int) ) ) (int); //设置一个函数作为信号处理程序
int raise(int sig); //函数 raise 把信号 sig 送给正在执行的程序,执行成功返回 0,否则返回非 0。
C 语言允许定义可接受一个可变参数列表的函数。stdarg.h 中定义了一种类型和三个宏用来访问一个可变参数表中额外的参数。
类型
va_list
宏
va_start
va_arg
va_end
stddef.h 中的内容比较杂,它提供了在独立环境中开发程序所要用的类型或宏。这些定义中的大部分也出现在其它头文件中。
类型
ptrdiff_t //两个指针相减的结果的有符号整数类型
size_t //是 sizeof 操作符的结果的无符号整数类型
wchar_t
宏
NULL //展开为实现定义的空指针常量
offsetof //展开为一个 size_t 类型的整值常量表达式
stdio.h
stdio.h 中声明了 3 种类型、一些宏和很多执行输入输出的函数。
stdio.h 中声明的大多数函数都是对一个流进行操作,这个流和一个打开的文件相关联。
stdio.h 中的函数可以分为文件操作函数、文件访问函数、格式化输入/输出函数、字符输入/输出函数、直接输入/输出函数、文件定位函数、错误处理函数。
类型
size_t
FILE //一个对象类型,可以记录控制流需要的所有信息,包括文件定位符、错误指示符、文件结束符、指向缓冲区的指针等
fpos_t //一个对象类型
宏
NULL
BUFSIZ // 展开为一个整值常量表达式,值 setbuf 函数使用的缓冲的大小
EOF // 展开为一个负的整值常量表达式,有几个函数返回 EOF 来说明文件的结束。
FOPEN_MAX // 表示实现支持的可以同时打开的文件数目的最大值
FILENAME_MAX // 表示实现可以打开的最长的文件名串的大小
SEEK_CUR, SEEK_END, SEEK_SET // 作为 fseek 函数的第三个参数使用,用于在一个文件中定位不同的位置。
strerr, stdin, stdout // 类型是指向 FILE 的指针,分别指向与标准错误流、标准输入流、标准输出流相关的 FILE 对象
对文件的操作
int remove(const char *filename) //删除给定的文件名 filename,以便它不再被访问。
int rename(const char *old_filename, const char *new_filename) //把 old_filename 所指向的文件名改为 new_filename。
FILE *tmpfile(void) //以二进制更新模式(wb+)创建临时文件。
char *tmpnam(char *str) //生成并返回一个有效的临时文件名,该文件名之前是不存在的
文件访问函数
int fclose(FILE *stream) //关闭流 stream。刷新所有的缓冲区。
int fflush(FILE *stream) //刷新流 stream 的输出缓冲区。
FILE *fopen(const char *filename, const char *mode) //使用给定的模式 mode 打开 filename 所指向的文件。
FILE *freopen(const char *filename, const char *mode, FILE *stream) //把一个新的文件名 filename 与给定的打开的流 stream 关联,同时关闭流中的旧文件。
void setbuf(FILE *stream, char *buffer) //定义流 stream 应如何缓冲。
int setvbuf(FILE *stream, char *buffer, int mode, size_t size) //另一个定义流 stream 应如何缓冲的函数。
格式化输入/输出函数
int fprintf(FILE *stream, const char *format, ...) //发送格式化输出到流 stream 中。
int printf(const char *format, ...) //发送格式化输出到标准输出 stdout。
int sprintf(char *str, const char *format, ...) //发送格式化输出到字符串。
int vfprintf(FILE *stream, const char *format, va_list arg) //使用参数列表发送格式化输出到流 stream 中。
int vprintf(const char *format, va_list arg) //使用参数列表发送格式化输出到标准输出 stdout。
int vsprintf(char *str, const char *format, va_list arg) //使用参数列表发送格式化输出到字符串。
int fscanf(FILE *stream, const char *format, ...) //从流 stream 读取格式化输入。
int scanf(const char *format, ...) //从标准输入 stdin 读取格式化输入。
int sscanf(const char *str, const char *format, ...) //从字符串读取格式化输入。
字符输入/输出函数
int fgetc(FILE *stream) //从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。
char *fgets(char *str, int n, FILE *stream) //从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时或到达文件末尾时停止。
int fputc(int char, FILE *stream) //把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。
int fputs(const char *str, FILE *stream) //把字符串写入到指定的流 stream 中,但不包括空字符。
int getc(FILE *stream) //从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。
int getchar(void) //从标准输入 stdin 获取一个字符(一个无符号字符)。
char *gets(char *str) //从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
int putc(int char, FILE *stream) //把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。
int putchar(int char) //把参数 char 指定的字符(一个无符号字符)写入到标准输出 stdout 中。
int puts(const char *str) //把一个字符串写入到标准输出 stdout,直到空字符,但不包括空字符。换行符会被追加到输出中。
int ungetc(int char, FILE *stream) //把字符 char(一个无符号字符)推入到指定的流 stream 中,以便它是下一个被读取到的字符。
直接输入/输出函数
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) //从给定流 stream 读取数据到 ptr 所指向的数组中。
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) //把 ptr 所指向的数组中的数据写入到给定流 stream 中。
文件定位函数
int fgetpos(FILE *stream, fpos_t *pos) //获取流 stream 的当前文件位置,并把它写入到 pos。
int fseek(FILE *stream, long int offset, int whence) //设置流 stream 的文件位置为给定的偏移 offset,参数 offset 意味着从给定的 whence 位置查找的字节数。
int fsetpos(FILE *stream, const fpos_t *pos) //设置给定流 stream 的文件位置为给定的位置。参数 pos 是由函数 fgetpos 给定的位置。
long int ftell(FILE *stream) //返回给定流 stream 的当前文件位置。
void rewind(FILE *stream) //设置文件位置为给定流 stream 的文件的开头。
错误处理函数
void clearerr(FILE *stream) //清除给定流 stream 的文件结束和错误标识符。
int feof(FILE *stream) //测试给定流 stream 的文件结束标识符。当设置了与流关联的文件结束标识符时,该函数返回一个非零值,否则返回零。
int ferror(FILE *stream) //测试给定流 stream 的错误标识符。
void perror(const char *str) //把一个描述性错误消息输出到标准错误 stderr。首先输出字符串 str,后跟一个冒号,然后是一个空格。
int snprintf(char *str, size_t size, const char *format, ...) //格式字符串到 str 中。
stdlib.h 是一个大杂烩,它定义和声明了那些没有明显归属的宏和函数。
stdlib.h 定义了四个变量类型、一些宏和各种通用工具函数。
stdlib.h 中的函数可以分为 6 组:整型数学、常用算法(查找和排序、伪随机数生成)、字符类型转换、存储分配、环境接口、多字节转换。
变量
size_t, wchar_t, div_t, ldiv_t
宏
NULL
EXIT_FAILURE //exit 函数失败时返回的值
EXIT_SUCCESS //exit 函数成功时返回的值
RAND_MAX; //rand 函数返回的最大值
MB_CUR_MAX
整形算术函数
int abs(int x); //返回 x 的绝对值
div_t div(int numer, int denom); //计算分子 number 除以分母 denom 得到的商与余数。返回的 div_t 是一个结构,由商 quot 和余数 rem 组成。
long int labs(long int x);//与 abs 相似,类型为 long int
ldiv_t ldiv(long int numer, long int denom);
查找和排序函数
void *bsearch(const void *key, const void *base, size_t n, size_t size, int(*compar)(const void*,const void*) );
//参数依次为:要查找的元素值,数组地址,数组长度,元素字节数,比较方式
void qsort(void *base,size_t n, size_t size, int(*compar)(const void*,const void*));
//参数依次为:数组名,数组长度,每个元素的字节数,比较方式(从大到小或从小到大)
伪随机数生成
int rand(void);//返回值在 0~RAND_MAX 之间的伪随机数
void srand(unsigned int seed);
//srand 函数是随机数发生器的初始化函数。seed?是一个整型值,用于伪随机数生成算法播种。如果使用相同的 seed,后面的 rand 函数会出现一眼的随机数。
字符类型转换函数
double atof(const char *nptr); //把 nptr 所指字符串的初始部分转换为 double 类型的表示并返回
int atoi(const char *nptr); //把 nptr 所指字符串的初始部分转换为 int 类型的表示并返回
long int atol(const char *nptr); //把 nptr 所指字符串的初始部分转换为 long int 类型的表示并返回
double strtof(const char *nptr, char **endptr);
//把参数?nptr?所指向的字符串转换为一个 double 类型的表示并返回,如果没有转换就返回 0。如果 endptr 不为空,指向 nptr 中数字之后的字符串的指针就保存在 endptr 中
long int strtol(const char *nptr, char **endptr, int base);
//把参数?nptr?所指向的字符串转换为一个 long int 类型的表示并返回,如果没有转换就返回 0。base 必须在 2~36 之间或取 0。
unsigned long int strtoul(const char *nptr, char **endptr, int base);
//把参数?nptr?所指向的字符串转换为一个 unsigned long int 类型的表示并返回,如果没有转换就返回 0。base 必须在 2~36 之间或取 0。
内存管理函数
void *calloc(size_t n,size_t size);//分配 n 个大小为 size 的内存块,并返回指向它的指针
void *malloc(size_t size);//分配大小为 size 的内存块,并返回指向它的指针,用法:int* ptr = (int*)malloc(sizeof(int));
void *realloc(void*ptr,size_t size);//重新分配内存。ptr指向原来的内存空间,返回指向新的内存空间的指针
void free(void *ptr);//释放分配的内存空间
环境接口函数
void?abort();???????????????????//使一个异常程序终止
int?atexit(void?(*func)(void));?//当程序正常终止时,调用指定的函数?func
void?exit(int?status);??????????
//使程序正常终止,控制权返回给宿主环境。如果?status?是?0?或?EXIT_SUCCESS?表示成功终止,如果?status?是?EXIT_FAILURE?表示不成功终止。status?为其他值的含义由实现定义
char?*getenv(const?char?*name);?//搜索宿主环境的环境变量表,查找一个能与?name?匹配的串,并返回相关的值。
int?system(const?char?*string);?//把?string?指向的串传递给宿主环境,然后命令处理程序按照实现定义的方式执行它。
string.h 定义了一个变量类型、一个宏和各种操作字符数组的函数。
变量
size_t
宏
NULL
函数
void *memchr(const void *str, int c, size_t n); //在参数?str?所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置。
int memcmp(const void *str1, const void *str2, size_t n) //把 str1 和 str2 的前 n 个字节进行比较。
void *memcpy(void *dest, const void *src, size_t n) //从 src 复制 n 个字符到?dest。
void *memmove(void *dest, const void *src, size_t n) //另一个用于从?src?复制 n 个字符到?dest?的函数。
void *memset(void *str, int c, size_t n) //复制字符 c(一个无符号字符)到参数?str?所指向的字符串的前 n 个字符。
char *strcat(char *dest, const char *src) //把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
char *strchr(const char *str, int c) //在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置,返回对应指针。
char *strrchr(const char *str, int c) //在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置,返回对应指针。
char *strpbrk(const char *str1, const char *str2) //检索字符串?str1?中第一个匹配字符串?str2?中字符的字符,不包含空结束字符,并返回该字符位置。
time.h 定义了四个类型、两个宏和各种操作日期和时间的函数。
time.h 中定义的函数可以分为两类:获取时间的函数(包括 clock 和 time)和转换时间格式的函数(包括其他所有函数)。
这些函数中有许多是不安全的,在 VS 中使用会报错,需要使用对应的安全版本。
变量
size_t //是无符号整数类型,它是 sizeof 关键字的结果。
clock_t //这是一个适合存储处理器时间的类型。
time_t //这是一个适合存储日历时间的类型。表示的是自纪元 Epoch(协调世界时 UTC:1970-01-01 00:00:00)起经过的时间。类型为 _int64。
struct tm //这是一个用来保存时间和日期的结构。
{
int tm_sec; /* 秒,范围从 0 到 59????????*/
int tm_min; /* 分,范围从 0 到 59????????*/
int tm_hour; /* 小时,范围从 0 到 23????????*/
int tm_mday; /* 一月中的第几天,范围从 1 到 31????*/
int tm_mon; /* 月,范围从 0 到 11????????*/
int tm_year; /* 自 1900 年起的年数????????*/
int tm_wday; /* 一周中的第几天,范围从 0 到 6????*/
int tm_yday; /* 一年中的第几天,范围从 0 到 365????*/
int tm_isdst; /* 夏令时????????????????*/
}
宏
NULL //这个宏是一个空指针常量的值。
CLOCKS_PER_SEC //这个宏表示每秒的处理器时钟个数。
获取时间的函数
两个获取时间的函数:clock 可以用来计算精确到微秒级的时间段。time 用来获取现实的日历时间。
clock_t clock(void) //返回程序执行起(一般为程序的开头),处理器时钟所使用的时间。
time_t time(time_t *timer) //获取当前日历时间,并把它编码成 time_t 格式。返回的是自纪元 Epoch(协调世界时 UTC:1970-01-01 00:00:00)起经过的时间。
//如果参数 timer 不是空指针,返回的结果也会存储到 timer 指向的对象中。
转换时间格式的函数
char *asctime(const struct tm *timeptr); //返回一个指向字符串的指针,它代表了结构 timeptr 的日期和时间。
//字符串的格式是:Www Mmm dd hh:mm:ss yyyy,其中,Www?表示星期几,Mmm?是以字母表示的月份,dd?表示一月中的第几天,hh:mm:ss?表示时间,yyyy?表示年份。
char *ctime(const time_t *timer); //返回一个表示当地时间的字符串,当地时间是基于参数 timer。
double difftime(time_t time1, time_t time2); //返回 time1 和 time2 之间相差的秒数 (time1-time2),注意是前者减去后者。
struct tm *gmtime(const time_t *timer); //timer 的值被分解为 tm 结构,并用协调世界时(UTC)也被称为格林尼治标准时间(GMT)表示。
struct tm *localtime(const time_t *timer) //timer 的值被分解为 tm 结构,并用本地时区表示。
time_t mktime(struct tm *timeptr) //把 timeptr 所指向的结构转换为一个依据本地时区的 time_t 值。
size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr) //根据 format 中定义的格式化规则,格式化结构 timeptr 表示的时间,并把它存储在 str 中。