The Standard C Library
The Standard C Library
--------------经典的基础
C的标志库函数是学习和使用C语言的基础,是编写经典C程序的基础,是学习其他计算机知识的基础.C标志库中一共包含了15个头文件:
<assert.h> <ctype.h> <stdio.h> <stdlib.h> <string.h> <limits.h> <float.h> <time.h>
<math.h> <setjmp.h> <signal.h> <stdarg.h> <stddef.h> <errno.h> <locale.h>
1:<assert.h>
NDEBUG
NDEBUG宏是调试开关,当使用#include NDEBUG时程序为非调试状态,这种状态下调试宏assert不起作用。
assert
调试宏assert只有在程序处于调试状态下才发挥作用,它的使用形式如下:assert(expression);当条件为假时会在屏幕中输出如下的调试信息:“Assertion failed:expression, file xyz, line nnn”,其中xyp是assert所在的文件名,nnn为assert在该文件中的位置。
assert宏还有许多用法,请参看《Writing Clean Code》第二章设计并使用断言。
2:<stdio.h>
<stdio.h>下面的类型,宏,函数都是分类的
其他:
size_t sizeof返回的值
NULL 空指针
文件:
FILE 文件的类型
fpos_t 文件中指针的位置
EOF 文件末尾<0
FILENAME_MAX 文件名最大值>0
FOPEN_MAX 同时打开文件的最大值>8
SEEK_SET 文件头
SEEK_CUR 文件当前位置
SEEK_END 文件末尾
打开文件
FILE *fopen(const char *filename,const char *mode);
更改当前流相关的文件
FILE *freopen(const char *filename,const char *mode,FILE *stream);
关闭文件
int fclose(FILE *stream);
清除流中的错误标志或文件末尾标志
void clearerr(FILE *stream);
测试流上的文件末尾标志
int feof(FILE *stream);
测试流上的错误标志
int ferror(FILE *stream);
将一个字符放回到流中
int ungetc(int c, FILE *stream);
从流中读一个字符
int fgetc(FILE *stream);
int getc(FILE *stream);/* 与fgetc相同但是可以用宏实现该函数 */
写一个字符到一个流
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
从流中获取一个字符串
char *fgets(char *s, int n, FILE *stream);
写一个字符串到一个流
int fputs(const char *s, FILE *stream);
打印一个格式化数据到一个流
int fprintf(FILE *stream,const char *format, ...);
使用一个参量列表指针格式化到流的数据
int vfprintf(FILE *stream,const char *format, va_list ap);
从一个流中读取格式化数据
int fscanf(FILE *stream, const char *format, ...);
从一个流中读数据
size_t fread(char *buffer,size_t size,size_t count,FILE *stream);
写数据到一个流
int fwrite(const char *buffer, size_t size, size_t count,
FILE *stream);
获取流的文件位置指示符
int fgetpos(FILE *stream, fpos_t *pos);
设置流位置指示符
int fsetpos(FILE *stream, const fpos_t *pos);
移动文件指针到一个指定的位置
int fseek(FILE *stream, long offset, int origin);
获得文件指针相对于文件头的偏移量
long ftell(FILE *stream);
重新定位一个文件指针到文件开头
void rewind(FILE *steam);
删除一个文件
int remove(const char *path);
更改一个文件或目录
int rename(const char *oldname, const char *newname);
缓冲区:
_IOFBF
_IOLBF
_IONBF 缓冲区类型
BUFSIZE 缓冲区尺寸>=256
刷新一个流并清空与流相关的缓冲区的内容
int fflush(FILE *stream);
控制流的缓冲区,已经被setvbuf代替
void setbuf(FILE *stream, char *buffer);
控制流的缓冲区类型和缓冲区大小
int setvbuf(FILE *stream, char *buffer, int mode, size_t size);
将一个格式化数据写入一个字符串
int sprintf(char *buffer, const char *format, ...);
从字符串中读格式化数据
int sscanf(const char *buffer, const char *format, ...);
从参量列表指针格式化到字符串
int vsprintf(char *buffer, const char *format, va_list ap);
临时文件
L_tmpnam 临时文件名长度>0
TMP_MAX 产生唯一文件名的最大数目>=25
以二进制读写的方式建立一个临时文件
FILE *tmpfile(void);
建立一个临时文件名
char *tmpname(char *string);
标准流:
stdin 标准输入流
stdout 标准输出流
stderr 标准错误输出流
从stdin获得一个字符
int getchar(void);
把字符写道stdout
int putchar(int c);
从stdin中获取一行
char *gets(char *buffer);
写一个字符串到stdout
int puts(const char *string);
打印一个错误消息到stderr
void perror(const char *error);
打印格式化数据到stdout
int printf(const char *format, ...);
从stdin读格式化数据
int scanf(const char *format, ...);
从参量列表指针格式化到stdout
int vprintf(const char *format, va_list ap);
3:<stdlib.h>
<stdlib.h>中定义的函数都是工具类的函数可以分类学习
其他:
NULL
size_t
执行一个系统命令
int system(const char *command);
程序控制:
EXIT_SUCCESS
EXIT_FAILURE exit函数的推出参数
终止当前进程并返回一个错误代码
void abort(void);
在推出时执行指定的函数
int atexit(void(*func)(void));
终止调用进程
void exit(int status);
数学工具:
div_t 函数div的返回类型
ldiv_t 函数ldiv的返回类型
RAND_MAX rand函数返回的最大值
产生一个伪随机数
int rand(void);
设置一个随机起始点
void srand(unsigned int seed);
计算绝对值
int abs(int i);
计算一个long整数的绝对值
long labs(long l);
执行一个快速排序
void qsort(void *base, size_t count, size_t size,
int (*compare)(const void *elem1, const void *elem2));
执行一个排序数组的二叉查找
void *bsearch(const void *key, const void *base,
size_t count, size_t size,
int(*compare)(const void *elem1,const void *elem2)
);
计算两个数的商与余数
div_t div(int number, int denom);
计算两个long整数的商和余数
ldiv_t ldiv(long number, long denom);
字符/字符串工具
wchar_t 宽字符宽度
MB_CUR_MAX 多字节字符中的最大字节数
将字符串转换成双精度
double atof(const char *string);/*可含有非数字字符 */
将字符串转换成整数
int atoi(const char *string);
将字符串转换成长整形
long atol(const char *string);
把字符串转换成一个双精度值
double strtod(const char *string, char **endptr);/*可以含有非数字
字符,被截掉的字符存在endptr中*/
把字符串转换成长整形
long strtol(const char *string, char **endptr, int base);
把字符串转换成无符号长整形
unsigned long strtoul(const char *string, char **endptr, int base);
获取长度和确定一个多字节字符的有效性
int mblen(const char *s, size_t count);
将一个多字节字符序列转换成宽字符序列
size_t mbstowcs(wchar_t *wcstr, const char *mbstr, size_t count));
将一个多字节字符转换成对应的宽字符
int mbtowc(wchar_t *wchar, const char *mbchar, size_t count));
将一个宽字符序列转换成一个多字节字符序列
size_t wcstombs(char *mbstr, wchar_t *wcstr, size_t count));
将一个宽字符转换成一个多字节字符
int wctomb(char *mbchar, wchar_t wchar);
内存管理工具:
分配内存块
void *malloc(size_t size);
在内存中分配一个数组并初始化为0
void *calloc(size_t count, size_t size);
重新分配内存块
void *recalloc(void *memblock, size_t size);
释放一块内存
void free(void *memblock);
环境工具:
从当前环境中取得一个值
char *getenv(const char *varname);
4<ctype.h>
<ctype.h>头文件中定义了有关于字符操作的函数
判断一个字符是否为控制字符(0x00 ~ 0x1f 或 0x7f)
int iscntrl(int c);
判断一个字符是否为空白字符(0x09 ~ 0x0d 或 0x20)
int isspace(int c);
判断一个字符是否为可打印字符(0x20 ~ 0x7e)
int isprint(int c);
判断一个字符是否为非空格的其他可打印字符(0x21 ~ 0x7e)
int isgraph(int c);
判断一个字符是否为标点字符
int ispunct(int c);
判断一个字符是否为字母数字字符
int isalnum(int c);
判断一个字符是否为十进制数字字符
int isdigit(int c);
判断一个字符是否为十六进制数字字符
int isxdigit(int c);
判断一个字符是否为字母字符
int isalpha(int c);
判断一个字符是否为大写字母字符
int isupper(int c);
判断一个字符是否为小写字母字符
int islower(int c);
转换字符为小写
int tolower(int c);
转换字符为大写
int toupper(int c);
5<string.h>:
<string.h>中声明的函数都是关于c字符串和内存操作的函数
其他:
NULL
size_t
内存操作:
查找内存块中的一个字符
void *memchr(const void *buffer, int c, size_t count);
比较两个内存块中的字符
int memcmp(const void *buffer1,const void *buffer2,size_t count);
在在内存块之间拷贝字节
void *memcpy(void *dest, const void *src, size_t count);
移动内存块
void *memmove(void *dest, const void *src, size_t count);
用指定的字符填充内存
void *memset(void *dest, int c, size_t count);
对于以上的函数中的size_t count项使用需注意了
当你按如下方式使用是错误的
str = (char *)malloc(sizeof(char)*81);
strp = (char *)memchr(str, ‘u’, sizeof(str));
free(str);
这是错误的str是指针它的长度不是整个字符串的长度,所以strp得不到正确的结果
应改为一个确定的数或者是实际数组的长度如strlen(str).
字符串操作:
字符串拼接
char *strcat(char *dest, const char *src);
向一个字符串末尾添加指定长度的字符串
char *strncat(char *dest, const char *src, size_t n);
在字符串中查找一个字符
char *strchr(const char *str, int c);
在一个字符串中查找一个字符最后一次出现
char *strrchr(const char *str, int c);
比较字符串
int strcmp(const char *str1, const char *str2);
比较两个字符串中指定长度的子串的大小
int strncmp(const char *str1, const char *str2, size_t n);
使用指定场所的信息比较字符串
int strcoll(const char *str1, const char *str2);
基于指定场所转换一个字符串
size_t strxfrm(char *dest, const char *src, size_t n);
拷贝一个字符串
char *strcpy(char *dest, const char *src);
将源字符串中指定长度的子串拷贝到目的串中
char *strncpy(char *dest, const char *src, size_t n);
查找一个子串
char *strstr(const char *string, const char *str);
查找string包含str中包含的字符的长度,例如:
string = “cabbage”; str = “abc”; return value = 5;
string = “cab bage”; str = “abc”; return value = 3;
string = “cafbbage”; str = “abc”; return value = 2;
string = “vcabbage”; str = “abc”; return value = 0;
size_t strspn(const char *string, const char *str);
在一个字符串中查找另一字符串的任意字符第一次出现的下标例如
string = “cabbage”; str = “ag”; return value = 1;
string = “xcabbage”; str = “ag”; return value = 2;
size_t strcspn(const char *string, const char *str);
返回在string中出现str字符集中的第一个字符的位置例如:
string = “kdkow adkf akkei”;str = “aeiw”;
return value = “w adkf akkei”;
char *strpbrk(const char *string, const char *str);
查找字符串中下一个语言符号
所谓的语言符号就是指用户定义的表示一个意义的整体,string是字符串,str是包含分割语言符合的分隔符的集合.使用方法例如:
token = strtok(string,str);
while(token != NULL)
{
puts(token);
token = strtok(NULL, str);
}
如
string = “kks\niiwo jfie\twlk,diwpob.owf’ksif\nli”;
str = “ \n\t,.’”;
结果为:
kks
iiwo
jfie
wlk
diwpob
owf
ksif
li
如
str = “w”;
结果为:
kks\nii
o jfie\t
lk,di
pob.o
f’ksif\nli
char *strtok(char *string, const char *str);
通过系统错误编号来获得系统错误消息
char *strerror(int errorcode);
获取字符串有效长度(不包括’\0’)
size_t strlen(const char *str);
6<limits.h>:
<limits.h> 中定义了整形的各种形式的边界值
char
CHAR_BIT 一个char占的位数
MB_LEN_MAX 多字节中char占的字节数
CHAR_MAX
CHAR_MIN
SCHAR_MAX
SCHAR_MIN
UCHAR_MAX
short
SHRT_MAX
SHRT_MIN
USHRT_MAX
int
INT_MAX
INT_MIN
UINT_MAX
long
LONG_MAX
LONG_MIN
ULONG_MAX
7<stddef.h>:
NULL
size_t
wchar_t
ptrdiff_t 指针之间的差值
size_t offsetof(structName,memberName); 结构成员相对于结构的偏移量
8<time.h>
NULL
size_t
CLOCKS_PER_SEC 每秒的时钟数
CLK_TCK 每秒的时钟数被CLOCKS_PER_SEC代替
clock_t clock函数的返回类型表示进程的逝去时钟数
time_t time等函数的返回值表示日历时间
struct tm
{
int tm_sec; 秒(0-59)
int tm_min; 分钟(0-59)
int tm_hour; 小时(0-24)
int tm_mday; 月中的天数(多少号)(1-31)
int tm_mon; 月份(0-11)
int tm_year; 年份从1900年开始
int tm_wday; 星期(0-6,星期日=0)
int tm_yday; 一年中的日期(0-365,1月1号 = 0)
int tm_isdst; 夏令时(正数有效,0无效,负数未定义)
};
返回调用进程使用的时钟数
clock_t clock(void);
获取系统时间(从1970,1,1 00:00:00 开始到现在的的秒数)
timer可以为NULL表示只返回不存储
time_t time(time_t *timer);
返回两个时间的差值
double difftime(time_t time1, time_t time2);
将time_t转换成字符串
char *ctime(const time_t *timer);
转换一个时间值有time_t转换到struct tm
struct tm *locattime(const time_t *timer);
gmtime使用UTC世界时间代码而不是本地时间
struct tm *gmtime(const time_t *timer);
将struct tm转换成time_t
time_t mktime(struct tm *timer);
localtime gmtime mktime使用同一个struct tm静态结构.每次调用前都清除其中的容
将struct tm转换成字符串
char *asctime(const struct tm *timer);
格式化一个时间字符串
size_t strftime(char *dest,size_t size,const char *format,
const struct tm *timer);
9<float.h>:
<float.h>与<limits.h>一样是定义边界值的,<float.h>定义的是浮点数的边界值
double
DBL_DIG double小数点后面精确的位数
DBL_EPSILON 小的正数,double的0跨度值
DBL_MANT_DIG 尾数中的位数
DBL_MAX 最大值
DBL_MAX_10_EXP 最大10进制指数
DBL_MAX_EXP 最大2进制指数
DBL_MIN 最小值
DBL_MIN_10_EXP 最小10进制指数
DBL_MIN_EXP 最小2进制指数
float
FLT_DIG float小数点后面精确的位数
FLT_EPSILON 小的正书,float的0跨度值
FLT_MANT_DLG 尾数中的位数
FLT_MAX 最大值
FLT_MAX_10_EXP 最大10进制指数
FLT_MAX_EXP 最大2进制指数
FLT_MIN 最小值
FLT_MIN_10_EXP 最小10进制指数
FLT_MIN_EXP 最小2进制指数
FLT_RADIX 进制基数
FLT_ROUNDS 加法舍入
long double
LDBL_DIG long double小数点后面精确的位数
LDBL_EPSILON 小的正数,long double的0跨度值
LDBL_MANT_DLG 尾数中的位数
LDBL_MAX 最大值
LDBL_MAX_10_EXP 最大10进制指数
LDBL_MAX_EXP 最大2进制指数
LDBL_MIN 最小值
LDBL_MIN_10_EXP 最小10进制指数
LDBL_MIN_EXP 最小2进制指数
10<math.h>
<math.h>中定义了数学函数
HUGE_VAL 最大的可表示的双精度值,这个值是由许多数学函数错误时返回的,有的函数返回-HUGE_VAL
EDOM 当传递的参数类型或数值错误时errno被赋予这个值
ERANGE 当数值超出浮点数的范围时errno被赋予这个值
三角函数
计算正弦
double sin(double x);
计算双曲线的正弦
double sinh(double x);
计算余弦
double cos(double x);
计算双曲线余弦
double cosh(double x);
计算正切
double tan(double x);
计算双曲线正切
double tanh(double x);
计算反余弦
double acos(double x);
计算反正弦
double asin(double x);
计算反正切
double atan(double x);
计算y/x的反正切
double atan2(double y, double x);
幂函数
计算x的y次幂
double pow(double x, double y);
计算平方根
double sqrt(double x);
计算指数值
double exp(double x);
计算自然对数
double log(double x);
计算以10为底的对数
double log10(double x);
浮点数操作函数
返回大于或等于x的最小整数
double ceil(double x);
计算浮点数的绝对值
double fabs(double x);
返回小于等于x的最大整数
double floor(double x);
计算x/y的余数
double fmod(double x, double y);
获得一个浮点数的尾数和指数
double frexp(double x, int *expptr);
从尾数和指数计算一个实数
double ldexp(double x, int exp);
把一个浮点数分解成小数和整数
double modf(double x, int *intptr);
11<errno.h>
errno 各种错误条件的事件赋予的错误代码如EDOM,ERANGE等
12<locale.h>
一个程序用于指定该程序使用哪一部分场所信息.
NULL
LC_ALL 影响所用的方面
LC_COLLATE 影响字符串校验函数strcoll,strxfrm
LC_CTYPE 影响<ctpye.h>中定义的字符处理函数
LC_MONETARY 影响localeconv返回的钱币格式信息
LC_NUMERIC 影响localeconv返回的非钱币格式的使用小数的数字信息,包括格式化,字符转换等
LC_TIME 影响strftime
struct lconv
{
成员 “C”场所值 场所范围 成员含义
char *currency_symbol; “” LC_MONETARY 当前场所的地方货币
符号
char *int_curr_symbol; “” LC_MONETARY 当前场所的国际货币
符号
char *mon_decimal_point; “” LC_MONETARY 货币量的小数点
char *mon_grouping; “” LC_MONETARY 货币量每个数字组的
尺寸
char *mon_thousands_sep; “” LC_MONETARY 货币量小数点左边的
数字分组字符
char *negative_sign; “” LC_MONETARY 负货币量表示符号的
字符串
char *positive_sign; “” LC_MONETARY 正货币量表示符号的
字符串
char *decimal_point; “.” LC_NUMERIC 非货币量的小数点
char *grouping; “” LC_NUMERIC 非货币量的每个数字
的尺寸
char *thousands_sep; “” LC_NUMERIC 非货币量小数点左边
数字分组字符
char frac_digits; CHAR_MAX LC_MONETARY 格式化货币量中小数
点右边的数字位数
char int_frac_digits; CHAR_MAX LC_MONETARY 国际格式化货币量中
小数点右边的数字位
数
char n_cs_precedes; CHAR_MAX LC_MONETARY 如果货币符号位于负
格式货币量之前,它
设置为1;如果符号在
值以后,设置为0
char n_sep_by_space; CHAR_MAX LC_MONETARY 如果货币符号通过空
格从负格式货币量中
分离则设置为1,没有
空格则为0
char n_sign_posn; CHAR_MAX LC_MONETARY 负格式货币量值正符
号的位置
char p_cs_precedes; CHAR_MAX LC_MONETARY 如果货币符号位于非
负格式货币量之前,
它设置为1,如果符号
值以后,设置为0
char p_sep_by_space; CHAR_MAX LC_MONETARY 如果货币符号通过空
格从非负格式货币量
中分离则设置为1,没
有空格为0
char p_sign_posn; CHAR_MAX LC_MONETARY 非负格式货币量值正
符号的位置
};
结构中的char *成员等于””的长度为0或不被当前场所支持,char成员为非负数CHAR_MAX的不被当前场所支持.
获得场所设置的详细信息
struct lconv *localeconv(void);
定义一个场所
char *setlocale(int category,const char *locale);
13<setjmp.h>
jmp_buf setjmp和longjmp使用的类型,用来保存和恢复应用程序环境
保存当前应用程序的环境
int setjmp(jmp_buf env);
恢复栈环境和执行场所
void longjmp(jmp_buf env, int val);
这两个函数的使用是有顺序性的一定是先调用setjmp来存储环境变量,再通过longjmp来恢复环境变量
它的执行过程是这样的(:前面的时行号)
#include <stdio.h>
#include <setjmp.h>
jmp_buf ebuf;
void f2(void);
int main(void)
{
int i;
puts("1");
0: i = setjmp(ebuf);
1: if(i == 0)
{
2: f2();
3: printf("This will not be printed");
}
4: printf("%d\n",i);
return 0;
}
void f2(void)
{
5: puts("2");
6: longjmp(ebuf,100);
}
上面的函数的执行过程是这样的
0行第一次执行setjmp时ebuf中保存了当前的系统环境变量,并返回0.接下来执行第1行,这是i等于0,执行第2行由次进入了f2中,第五行向stdout中打印了2,然后第6行调用了longjmp恢复了系统环境变量,注意这时函数的执行又回到了第0行而不是执行f2后面的第3行,这时setjmp返回的函数就不是0了而是longjmp中的100,所以接下来执行的第1行中的i等于100了直接执行第4行.所以第3行永远也没有机会执行.
14<signal.h>
信号
SIGABRT 异常中止,缺省动作是推出程序并返回推出码3
SIGFPE 浮点错误,例如溢出,除0或无效操作,缺省终止程序
SIGILL 非法指令,缺省终止程序
SIGINT CTRL+C中断,缺省调用INT23H中断
SIGSEGV 非法存储访问,缺省终止程序
SIGTERM 终止请求传送到程序,缺省终止程序
行为
SIG_DFL 使用系统缺省响应,如果调用程序使用流I/O,由运行库建立缓冲区不刷新.
SIG_IGN 忽略中断信号,这个值从不会为SIGFPE给出,因为该进程的浮点状态无定义
SIG_ERR 错误.
sig_atomic_t
发送一个信号给应用程序,如果以前使用signal安装了一个信号处理程序则执行该程序,没有则执行信号的缺省行为
int raise(int sig);
设置中断信号处理,signo是中断要处理的信号,必须是上面的信号之一,func是处理函数的地址或者使用上面的行为,如果func是函数的地址,则这个函数在调用signal时就被安装.
void (*signal(int signo,void(*func)(int)))(int);
按照如下的方法使用signal函数
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
jmp_buf env;
void fpHander(int signo);
int main(void)
{
int jmpflag;
double d1,d2,r;
0: if(signal(SIGFPE,fpHander) == SIG_ERR)
{
perror("Can't install the SIGFPE hander");
abort();
}
else
{
jmpflag = setjmp(env);
if(jmpflag == 0)
{
printf("Test for div:");
scanf("%lf%lf",&d1,&d2);
1: r = d1/d2;
printf("r:%G\n",r);
printf("d2 is not 0\n");
r = d1*d2*d2*d1*d2*d2;
2: printf("r:%G\n",r);
printf("r is not overflow\n");
3: if(d2 == 0)
4: raise(SIGFPE);
}
else
{
printf("Signal fixed\n");
}
}
return 0;
}
void fpHander(int signo)
{
printf("signo:%d\n",signo);
longjmp(env,-1);
}
一般的如果读入的d2为0的话,那么当执行第1行时就会引发浮点错误信号SIGFPE,而代用第0行安装的函数fpHander(但是在VC中好像不行,但TC中能通过)如果不能引发SIGFPE只好自己来引发SIGFPE了第4行调用了raise来引发SIGFPE错误使fpHander函数执行.
15<stdarg.h>
在这个头文件中定义了一些宏和类型,用来实现可变参数函数.
va_list 可变参数表类型.
va_start 设置可变参数表头的宏
va_arg 检索当前参数的宏
va_end 清除可变参数列表的宏,是的函数能够返回.