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 清除可變參數列表的宏,是的函數能夠返回.