一.通路C庫
如何通路C庫取決于實作,下面是一些可能的方法
1.自動通路:
2.檔案包含:
3.庫包含:
二.數學庫
以下涉及的角度均為弧度制
1.math.h庫
(1)幂函數:
求float x的平方根:float sqrtf(float x);
求double x的平方根:double sqrt(double x);
求long double x的平方根:long double sqrtl(long double x);
求float x的立方根:float cbrtf(float x);
求double x的立方根:double cbrt(double x);
求long double x的立方根:long double cbrtl(long double x);
求float x的float y次幂:float powf(float x,float y);
求double x的double y次幂:double pow(double x,double y);
求long double x的long double y次幂:long double powl(long double x,long double y);
//執行個體:
printf("%lf\n",sqrt(4));//結果:2.000000
printf("%f\n",cbrt(27));//結果:3.000000
printf("%f\n",pow(2,3));//結果:8.000000
(2)絕對值:
求int x的絕對值:int abs(int x);
求long x的絕對值:long llabs(long x);
求long long x的絕對值:long long llabs(long long x);
求float x的絕對值:float fabsf(float x);
求double x的絕對值:double fabs(double x);
求long double x的絕對值:long double fabsl(long double x);
//執行個體:
printf("%d\n",abs(22));//結果:22
printf("%d\n",abs(-5.43));//結果:5
printf("%lf\n",fabs(-5.43));//結果:5.430000
(3)三角函數:
求float x的反餘弦值:float acosf(float x);
求double x的反餘弦值:double acos(double x);
求long double x的反餘弦值:long double acosl(long double x);
求float x的正弦弦值:float asinf(float x);
求double x的正弦弦值:double asin(double x);
求long double x的正弦弦值:long double asinl(long double x);
求float x的反正切值:float atanf(float x);
求double x的反正切值:double atan(double x);
//無法區分π/4和5π/4
求long double x的反正切值:long double atanl(long double x);
求float y/float x的反正切值:float atan2f(float y,float x);
求double y/double x的反正切值:double atan2(double y,double x);
//可以區分π/4(=atan2(1,1))和5π/4(=atan2(-1.-1))
求long double y/long double x的反正切值:long double atan2l(long double y,long double x);
求float x的餘弦值:float cosf(float x);
求double x的餘弦值:double cos(double x);
求long double x的餘弦值:long double cosl(long double x);
求float x的正弦值:float sinf(float x);
求double x的正弦值:double sin(double x);
求long double x的正弦值:long double sinl(long double x);
求float x的正切值:float tanf(float x);
求double x的正切值:double tan(double x);
求long double x的正切值:long double tanl(long double x);
//執行個體:
printf("%f\n",acos(0));//結果:1.570796
printf("%f\n",asin(1));//結果:1.570796
printf("%f\n",atan(1));//結果:0.785398
printf("%f\n",atan2(1,1));//結果:0.785398
printf("%f\n",atan(-1));//結果:-0.785398
printf("%f\n",atan2(1,-1));//結果:2.356194
printf("%f\n",atan2(-1,1));//結果:-0.785398
printf("%f\n",cos(3.14));//結果:-0.999999
printf("%f\n",sin(1.57));//結果:1.000000
printf("%f\n",tan(0.785));//結果:0.999204
(4)指/對數函數:
求float x的以e為底的指數:float expf(float x);
求double x的以e為底的指數:double exp(double x);
求long double x的以e為底的指數:long double expl(long double x);
求float x的自然對數:float logf(float x);
求double x的自然對數:double log(double x);
求long double x的自然對數:long double logl(long double x);
求float x的以10為底的對數:float log10f(float x);
求double x的以10為底的對數:double log10(double x);
求long double x的以10為底的對數:long double log10l(long double x);
//執行個體:
printf("%f\n",exp(1));//結果:2.718282
printf("%f\n",log(exp(1)));//結果:1.000000
printf("%f\n",log10(10));//結果:1.000000
(5)取整:
求不小于float x的最小整數:float ceilf(float x);
求不小于double x的最小整數:double ceil(double x);
求不小于long double x的最小整數:long double ceill(long double x);
求不大于float x的最大整數:float floorf(float x);
求不大于double x的最大整數:double floor(double x);
求不大于long double x的最大整數:long double floorl(long double x);
//執行個體:
printf("%f\n",ceil(3.14));//結果:4.000000
printf("%f\n",ceil(3.98));//結果:4.000000
printf("%f\n",ceil(3));//結果:3.000000
printf("%f\n",floor(3.14));//結果:3.000000
printf("%f\n",floor(3.98));//結果:3.000000
printf("%f\n",floor(3));//結果:3.000000
(6)通過泛型選擇表達式選擇合适的函數版本:
#include <stdio.h>
#include <math.h>
#define RTD (180/4*atanl(1))
#define SQRT(X) _Generic((X),float:sqrtf,long double:sqrtl,default:sqrt)(X)
#define SIN(X) _Generic((X),float:sinf((X)/RTD),long double:sinl((X)/RTD),default:sin((X)/RTD))
int main(void) {
float x=45.0f;
double xx=45.0;
float s=SQRT(x);
double ss=SQRT(xx);
printf("%.17f\n",s);//結果:6.70820379257202150
printf("%.17Lf\n",ss);//結果:6.70820393249936940
float x2=45.0f;
double xx2=45.0;
float s2=SIN(x2);
double ss2=SIN(xx2);
printf("%.17f\n",s2);//結果:0.95605564117431641
printf("%.17Lf\n",ss2);//結果:0.95605565732762954
return 0;
}
2.tgmath.h庫:
tgmath.h中定義了泛型類型宏,與math.h中各double版函數同名,但會依據提供的參數類型展開為float/double/long double版函數:
#include <stdio.h>
#include <tgmath.h>
int main(void) {
float x=3.1415;
//調用sqrt()宏,展開為sqrtf()函數
printf("%d,%f\n",sizeof(sqrt(x)),sqrt(x));//結果:4,1.772428
//如果要調用sqrt()函數而非sqrt()宏:
printf("%d,%f",sizeof((sqrt)(x)),(sqrt)(x));//結果:8,1.772428
//也可以通過下式調用sqrt()函數:
//
return 0;printf("%d,%f",sizeof((*sqrt)(x)),(*sqrt)(x));
}
另外,如果編譯器支援複數運算,這些宏就也能展開為float complex/double complex/long double complex版函數
3.complex.h庫
(1)運算函數:
math.h相應的複數運算庫.函數名和math.h大體相同,隻是開頭多1個c,且傳回float complex/double complex/long double complex
//執行個體:見 (2) 部分
(2)取值函數:
傳回float complex x的實部:float crealf(float complex x);
傳回double complex x的實部:double creal(double complex x);
傳回long double complex x的實部:long double creall(long double complex x);
傳回float complex x的虛部:float cimagf(float complex x);
傳回double complex x的虛部:double cimag(double complex x);
傳回long double complex x的虛部:long double cimagl(long double complex x);
//執行個體:
#include <stdio.h>
#include <complex.h>
int main(void) {
float complex c=1+2i;
float complex rc=csqrtf(c);
printf("%d,%f,%f",sizeof(rc),crealf(rc),cimagf(rc));//結果:8,1.272020,0.786151
return 0;
}
三.字元,字元串與檔案庫
1.stdio.h庫
(1)字元(串)輸出函數:
進行格式化的輸出:int <n>=printf();
//參見 C語言基礎.常用指令,運算符,控制符.1
//參數說明:
n:傳回被輸出的字元數
輸出字元串到stdout:puts();
//參見 C語言細節.字元串.三.1
#########################################################################################
輸出單個字元到stdout:putchar(<c>);
//參見 C語言基礎.常用指令,運算符,控制符.1.(2) 部分
(2)字元(串)輸入函數:
要求進行格式化的輸入:int <n>=scanf();
//參見 C語言基礎.常用指令,運算符,控制符.3
//參數說明:
n:傳回成功讀取的資料項數
從stdin讀取整行輸入:gets();
//參見 C語言細節.字元串.二.2.(1)
從stdin讀取有長度上限的整行:gets_s();
//參見 C語言細節.字元串.二.2.(3)
#########################################################################################
從stdin讀取單個字元:<c>=getchar();
//參見 C語言基礎.常用指令,運算符,控制符.3.(2) 部分
(3)标準IO函數:
打開指定檔案:<fp>=fopen("<fname>","<mode>");
關閉指定檔案:fclose(<fp>);
從檔案中讀取字元:<ch>=getc(<fp>);
寫入指定字元的檔案中:putc(<ch>,<fp>);
//詳情參見 C語言細節.字元輸入/輸出.3.(4) 與 C語言細節.檔案的輸入與輸出.二 部分
(4)sprintf():
将資料寫入字元串:sprintf(<tstr>,"<content>"[,<param1>...]);
//參數說明:<content>/<param>同printf()
tstr:将資料寫入到該字元串
//應是1個有足夠空間的資料對象(如數組),而不能是指針
//執行個體:
#include <stdio.h>
int main(void) {
char b[10];
sprintf(b,"z%d",11);
printf("%s\n",b);//結果:z11
sprintf(b+3,"kkk");
printf("%s",b);//結果:z11kkk
return 0;
}
(5)檔案IO函數:
輸出格式化内容到檔案:fprintf(<fp>,"<content>"[,<param1>...]);
從檔案讀取格式化内容:fscanf(<fp>,"<format>",<varp>);
讀取有長度上限的整行内容:[<p>=]fgets(<var>,<len>,<pos>);
//參見 C語言細節.字元串.二.2.(2)
輸出字元串到指定位置:fputs("<str>",<pos>);
//參見 C語言細節.字元串.三.2
(6)随機通路函數:
将檔案中的光标移動到指定位置:int <r>=fseek(<fp>,<offset>,<mode>);
查找光标目前在檔案中的位置:long <fpos>=ftell(<fp>);
//參見 C語言細節.檔案的輸入與輸出.四.1 部分
(6)檔案重定向:
進行檔案重定向:FILE * <rp>=freopen(const char * filename,const char * mode,FILE * stream)
//參見 C語言細節.檔案的輸入與輸出.五 部分
2.string,h庫
注意:如果使用ANSI C之前的編譯器,不應加下述指令:
#include <string.h>
(1)strlen():
傳回字元串的字元長度:int <len>=strlen(<str>);
//即傳回字元串中有幾個字元(空字元'\0'不計入,是以strlen(<str>)+1才是<str>實際包含的字元數)
//參數說明:
str:字元數組或字元串常量
len:傳回字元串的字元長度
//執行個體1:
#include <stdio.h>
#include <string.h>
#define aaa "asdfgx"
int main(void) {
char name[5];
scanf("%s",name);//輸入:tyw
printf("%d,%d\n",strlen(name),strlen(aaa));//結果:3,6
return 0;
}
//執行個體2:
#include <stdio.h>
#include <string.h>
void change(char * string,unsigned int size) {
if (strlen(string)>size) {
string[size]='\0';
}
}
int main(void) {
char msg[]="Things should be as simple as possible,but not simpler.";
puts(msg);
change(msg,38);
puts(msg);
puts(msg+39);
return 0;
}
//結果:
Things should be as simple as possible,but not simpler.
Things should be as simple as possible
but not simpler.
(2)字元串的拼接:
拼接字元串:[char * <str1p>=]strcat(<str1>,<str2>);
//拼接後的字元串為"<str1><str2>",并且<str1>會被修改為拼接後的字元串
//相當于把<str2>中的字元按順序放到剩餘的配置設定給<str1>的記憶體空間中
//注意:拼接後<str1>隻在結尾有1個'\0',原本<str1>中的'\0'會被删掉
//是以strlen(<str1(拼接後)>)=strlen(<str1(拼接前)>)+strlen(<str2>)+1
//參數說明:
str1,str2:要拼接的字元串
//因為<str1>會被修改為拼接後的字元串,是以不應給<str1>傳入字元串字面量,否則得不到拼接後的字元串
//而<str2>不變,是以可以傳入字元串字面量
str1p:傳回str1的位址
//執行個體:
#include <stdio.h>
#include <string.h>
int main(void) {
char msg[30];
char begin[]="I want to say that ";
gets(msg);
puts(msg);
strcat(begin,msg);
puts(begin);
puts(msg);
printf("end");
return 0;
}
//結果:
blablabla
blablabla
I want to say that blablabla
blablabla
end
//#######################################################################################
//strcat()的問題:
strcat()無法檢查配置設定給<str1>的記憶體空間是否足以容納拼接後的字元串,如果空間不夠大,多出來的字元就會溢出
到相鄰的存儲單元,進而引發種種問題,如:
#include <stdio.h>
#include <string.h>
int main(void) {
char msg[30];
char begin[]="I want to say that ";
gets(msg);
puts(msg);
strcat(begin,msg);
puts(begin);
puts(msg);
printf("end");
return 0;
}
//結果:
I am your father.
I am your father.
I want to say that I am your father.
her.
end
要解決這個問題,可以使用strlen()檢測字元串長度,也可以使用strncat()
//#######################################################################################
進行有上限的字元串拼接:[char * <str1p>=]strncat(<str1>,<str2>,<n>);
//相當于把<str2>中的字元按順序放到剩餘的配置設定給<str1>的記憶體空間中
//放完<str2>的所有字元(碰到'\0')或添加的字元數達到上限時就停止
//參數說明:<str1>/<str2>/<str1p>同strcat()
n:指定最大添加的字元數
//執行個體:
#include <stdio.h>
#include <string.h>
int main(void) {
char msg[25];
char begin[]="I want to say that ";
gets(msg);
puts(msg);
strncat(begin,msg,5);
puts(begin);
puts(msg);
printf("end");
return 0;
}
//結果:
I am your father.
I am your father.
I want to say that I am
I am your father.
end
(3)字元串的比較:
比較2個字元串的内容是否相同:int <r>=strcmp(<str1>,<str2>);
//如果直接使用運算符=或!=進行比較,則比較的是字元串的位址而非内容
//該函數通過關系運算符來比較字元串
//因為數組表示法/指針表示法/字元串字面量都被視為指針
//參數說明:
str1,str2:要進行比較的2個字元串
//注意:不能是字元(如"A"合法,'A'不合法)
r:如果2個字元串相同,傳回0;否則傳回非0值
//執行個體:
#include <stdio.h>
#include <string.h>
int main(void) {
char in[25];
char pre[]="hahaha";
gets(in);
while(strcmp(in,pre)) {
printf("wrong answer,please input again\n");
gets(in);
}
puts(in);
printf("end");
return 0;
}
//結果:
ahahah
wrong answer,please input again
hahaha
hahaha
end
注意:strcmp()比較的是字元串而不是這個字元數組
char a[5]="aaa";
char b[10]="aaa";
printf("%d",strcmp(a,b));//結果:0
//雖然數組a,b占用的空間大小不同,但存儲的字元串的内容相同,是以strcmp()傳回0
//#######################################################################################
比較字元串的前指定個字元:strncmp(<str1>,<str2>,<n>);
//比較規則同strcmp()
//參數說明:<str1>,<str2>同strcmp()
n:指定隻比較前n個字元
//執行個體:
printf("%d\n",strncmp("apples","apple",5));//結果:0
printf("%d\n",strncmp("app","apple",3));//結果:0
printf("%d\n",strncmp("aaacd","aabcd",5));//結果:-1
- 傳回值問題:
//規則:
①如果2個字元串完全相同,傳回0;如果<str1>的首字元在按ASCII碼表中靠前,傳回負值;否則傳回正值
嚴格來說,是按"機器排列順序"進行比較,不過通常都是ASCII碼
②如果2個字元串的首字元相同,則依次比較之後的字元(仍按照①的規則),直到第1個不同的字元
③在某些系統中,傳回的正/負值隻會是±1,另一些系統中則是ASCII碼的內插補點
不過通常情況下,傳回的具體值并不重要,需要關注的隻是其為正/負/0
printf("%d\n",strcmp("AAA","AAA"));//結果:0
printf("%d\n",strcmp("AAA","BBB"));//結果:-1
printf("%d\n",strcmp("BBB","AAA"));//結果:1
printf("%d\n",strcmp("A","B"));//結果:-1
printf("%d\n",strcmp("B","A"));//結果:1
printf("%d\n",strcmp("C","A"));//結果:1//某些系統中會傳回2,即二者的ASCII碼之差
printf("%d\n",strcmp("Z","a"));//結果:-1
printf("%d\n",strcmp("apples","apple"));//結果:1
//在該比較中,前面的字元均相同,最後的比較是'\0'和's',因為'\0'的ASCII碼為0,是以傳回正值
printf("%d\n",strcmp("a","/"));//結果:1
- 字元的比較問題:
可以使用關系運算符來比較字元,如:
char ch=getchar();
if (ch=='q') {
printf("OK\n");
}
但不要把字元作為strcmp()的參數傳入
(4)字元串的拷貝:
拷貝整個字元串:[char * <rp>=]strcpy(<tstr>,<fstr>);
//不僅會拷貝變量本身,也會拷貝字面量:即(&<fstr>!=&<tstr>)&&(<fstr>!=<tstr>)
//注意:<fstr>是該變量指向的字元串字面量的記憶體位址,&<fstr>則是該變量的位址
//參數說明:參數順序可以類别指派表達式
tstr:将<fstr>拷貝到<tstr>("目标字元串")
//應是1個有足夠空間的資料對象(如數組)
//不能是指針,因為說明數組将配置設定儲存資料的空間,而聲明指針隻配置設定儲存1個位址的空間
fstr:要拷貝的字元串("源字元串")
//可以是指針/數組/字元串字面量
rp:傳回<tstr>的位址
//執行個體:
#include <stdio.h>
#include <string.h>
int main(void) {
char * a="aaaa";
char b[4];
int r=strcpy(b,a);
printf("%s,%s,%d,%d,%d,%d\n",a,b,a,b,&a,&b);
//結果:aaaa,aaaa,4210688,6487568,6487576,6487568
printf("%d",r);//結果:6487568
return 0;
}
//注意:<tstr>不一定指向某個數組的開始位置,也可以指向某數組中間的某位置
#include <stdio.h>
#include <string.h>
int main(void) {
char * a="aaaa";
char b[10]="bbb";
int r=strcpy(b+3,a);
printf("%s,%s,%d,%d,%d,%d\n",a,b,a,b,&a,&b);
//結果:aaaa,bbbaaaa,4210688,6487552,6487568,6487552
//這裡因為用的是b+3,是以把"bbb"後面的'\0'覆寫掉了
printf("%d\n",r);//結果:6487555
strcpy(b+8,"d");
printf("%s",b);//結果:bbbaaaa//因為在輸出'd'之前就遇到了'\0'
return 0;
}
//#######################################################################################
有上限的字元串拷貝:[char * <rp>=]strncpy(<tstr>,<fstr>,<n>);
//除了存在拷貝字元數的上限外,均與strcpy()相同
//注意:由于不一定完全拷貝<fstr>,拷貝後的<tstr>結尾不一定有'\0',可能需要自行設定
//參數說明:<tstr>/<fstr>/<rp>同strcpy()
n:指定拷貝的最大字元數
//執行個體:
#include <stdio.h>
#include <string.h>
int main(void) {
char * a="aaaa";
char b[10]="bbb";
int r=strncpy(b+3,a,2);
printf("%s,%d,%d",b,b,r);//結果:bbbaa,6487552,6487555
return 0;
}
(5)字元的查找:
查找首個指定字元:char * <fep>=strchr(<s>,<c>);
//參數說明:
s:指定在哪個字元串中進行查找
c:指定要查找的字元
//可以傳入字元,也可以傳入整數
fep:傳回1個指向<c>首次出現的位置的指針(如果在<s>中沒有找到<c>,則傳回1個空指針)
//注意:結尾處的'\0'也在查找範圍内
//執行個體1:
#include <stdio.h>
int main(void) {
char a[10]="mmadsaj";
char * p=strchr(a,'a');
printf("%d,%d",a,p);//結果:6487552,6487554
return 0;
}
//執行個體2:
#include <stdio.h>
int main(void) {
char a[10]="mmadsaj";
char * p=strchr(a,'z');
printf("%d,%d",a,p);
return 0;
}
//#######################################################################################
查找首個指定的多個字元:char * <fp>=strpbrk(<fstr>,<astr>);
//參數說明:
fstr:指定在該字元串中進行查找
astr:所有要查找的字元構成的字元串
fp:如果<astr>中的任一字元在<fstr>中,傳回指向<fstr>中第1個包含在<astr>中的字元的指針;否則傳回空指針
//執行個體1:
#include <stdio.h>
int main(void) {
char a[10]="mmadsaj";
char * p=strpbrk(a,"fda");
printf("%d,%s",a,p);//結果:6487552,adsaj
return 0;
}
//執行個體2:
#include <stdio.h>
int main(void) {
char a[10]="mmadsaj";
char * p=strpbrk(a,"zxy");
printf("%d,%d",a,p);//執行個體:6487552,0
return 0;
}
//#######################################################################################
查找尾個指定字元:char * <lep>=strrchr(<s>,<c>);
//參數說明:<s>/<c>同strchr()
lep:傳回1個指向<c>最後1次出現的位置的指針(如果在<s>中沒有找到<c>,則傳回1個空指針)
//注意:結尾處的'\0'也在查找範圍内
//#######################################################################################
查找首個指定子字元串:char * <ep>=strstr(<fstr>,<astr>);
//參數說明:
fstr:指定在該字元串中查找
astr:指定要查找的子字元串
ep:傳回指向<fstr>中<astr>首次出現的位置的指針(如果<astr>不出現在<fstr>中,傳回空指針)
//執行個體:
#include <stdio.h>
int main(void) {
char a[10]="mmadsaj";
char * p=strstr(a,"ads");
printf("%d,%d\n",a,p);//結果:6487552,6487554
p=strstr(a,"asa");
printf("%d,%d",a,p);//結果:6487552,0
return 0;
}
//#######################################################################################
查找尾個指定子字元串:char * <ep>=strrstr(<fstr>,<astr>);
//參數說明:其他同上
ep:傳回指向<fstr>中<astr>最後1次出現的位置的指針(如果<astr>不出現在<fstr>中,傳回空指針)
(6)拷貝(任意類型的)數組:
拷貝數組:void * memcpy(void * restrict s1,const void * restrict s2,size_t n);
拷貝數組:void * memmove(vois * s1,const void * s2,size_t n);
//差別在于memcpy()使用restrict關鍵字,即假設2個内容區域沒有重疊,進而允許編譯器進行優化
//如果使用memcpy()時2個内容區域有重疊,該行為是未定義的
//注意:這2個函數不知道資料的類型,而隻負責拷貝位元組,并且拷貝時不會進行資料類型轉換
//參數說明:
s1,s2:從s2指向的位置拷貝到s1指向的位置
n:指定待拷貝的内容占用的位元組數
//執行個體:
#include <stdio.h>
#include <string.h>
int main(void) {
int a[5]={1,2,3,4,5};
int b[4];
memmove(b,a,4*sizeof(int));
int i;
for (i=0;i<4;i++) {
printf("%d ",b[i]);
}
return 0;
}
//結果:
1 2 3 4
(7)重置數組:
将str中的前n個字元設為c:void * memset(void * str,int c,size_t n);
//參數說明:
str:指定字元串
c:指定要設為的字元
n:指定設定前幾個字元
//執行個體:
#include <stdio.h>
#include <string.h>
int main(void) {
char s[]="I am your father";
printf("%s\n",s);
memset(s,114,4);
printf("%s\n",s);
memset(s+4,'e',2);
printf("%s",s);
return 0;
}
//結果:
I am your father
rrrr your father
rrrreeour father
3.ctype.h庫
ctype.h中的函數通常作為"宏"(Macro)來實作
(1)字元測試函數:
如果為指定類型,傳回[真];否則傳回[假]
下述函數中的參數c都是字元或字元變量,不能是字元串
是否是字母或數字:isalnum(<c>);
是否是字母:isalpha(<c>);
是否是标準的空白字元或本地化指定為空白的字元:isblank(<c>);
标準的空白字元包括空格,水準制表符,換行符
是否是控制字元(如Ctrl+B):iscntrl(<c>);
是否是數字:isdigit(<c>);
是否是除空格外的任意可列印字元:isgraph(<c>);
是否是小寫字母:islower(<c>);
是否是可列印字元:isprint(<c>);
是否是标點符号:ispunct(<c>);
包括除空格/字母/數字外的任何可列印字元)
是否是空白字元:isspace(<c>);
除isblank()包括的字元外,還包括換頁符,回車符,垂直制表符
是否是大寫字母:isupper(<c>);
是否是16進制數字元:isxdigit(<c>);
(2)字元映射函數:
将大寫字母轉換成小寫字母:<c1>=tolower(<c2>);
将小寫字母轉換成大寫字母:<c1>=toupper(<c2>);
//注意:不是直接在原變量上進行轉換,需要指派給新變量
//參數說明:
c2:要轉換的字元
c1:轉換後的字元
//執行個體:
char a='d';
a=toupper(a);
printf("%c\n",a);//結果:D
a=tolower(a);
printf("%c\n",a);//結果:d
四.通用工具庫
1.stdlib.h庫
(1)将字元串轉換為數字:
将str轉換為整數:int <i>=atoi("<istr>");
//參數說明:
istr:指定要進行轉換的字元串
//注意:該字元串的内容必須以整數開始
//實際上是指向要轉換的字元串的指針
i:傳回轉換後得到的整數值
//執行個體:
#include <stdio.h>
int main(void) {
int a=atoi("123");
int b=atoi("a");
int c=atoi("123.93");
int d=atoi("-3");
int d=atoi("-31efd");
printf("%d\n",a);//結果:123
printf("%d\n",b);//結果:0//轉換失敗
//注:在C标準中,這種情況是未定義的
printf("%f\n",c);//結果:123.000000//截斷到了整數位
printf("%d\n",d);//結果:-3
printf("%d\n",e);//結果:-31//隻轉換開頭處的整數
return 0;
}
//#######################################################################################
将str轉換為double:double <d>=atof("<dstr>");
//參數說明:類似于atoi()
//#######################################################################################
将str轉換為long:long <l>=atol("<lstr>");
//參數說明:類似于atoi()
//#######################################################################################
檢查并将str轉換為long:long <l>=strtol("<lstr>",<eptr>,<base>);
//會先檢查字元串是否以數字開始
//可以指定輸入的數字字元串采用的進制(輸出統一采用10進制)
//參數說明:<lstr>類似于atoi()
eptr:指向結束字元的指針的位址
//如輸入10進制數字"31at",結束在'a'處,則<eptr>是指向'a'的指針的位址
//函數執行完成後,該位址會被儲存在<eptr>中
base:指定輸入的數字字元串采用的進制
//最高到36進制(此時'a'~'z'均作為數字)
//執行個體:
#include <stdio.h>
#define LIM 30
int main(void) {
char n[LIM];
char * end;
long v;
while (gets(n),n[0]!='q') {
v=strtol(n,&end,10);
printf("base 10 input:%ld,end at %s\n",v,end);
v=strtol(n,&end,16);
printf("base 16 input:%ld,end at %s\n",v,end);
v=strtol(n,&end,36);
printf("base 36 input:%ld,end at %s\n",v,end);
}
return 0;
}
//結果:
10
base 10 input:10,end at
base 16 input:16,end at
base 36 input:36,end at
10atom
base 10 input:10,end at atom
base 16 input:266,end at tom
base 36 input:60971206,end at
z
base 10 input:0,end at z
base 16 input:0,end at z
base 36 input:35,end at
q
//#######################################################################################
檢查并将str轉換為unsigned long:unsigned long <ul>=strtoul("<ulstr>",<eptr>,<base>);
//會先檢查字元串是否以數字開始;可以指定輸入的數字字元串采用的進制(輸出統一采用10進制)
//參數說明:<ulstr>類似于atoi(),<eptr>/<base>類似于<strtol>
//#######################################################################################
檢查并将str轉換為double:double <d>=strtod("<dstr>",<eptr>);
//會先檢查字元串是否以數字開始
//參數說明:類似于atoi(),<eptr>類似于<strtol>
(2)将數字轉換成字元串:
将整數轉換成str:itoa();
//#######################################################################################
将浮點數轉換成str:itoa();
//#######################################################################################
上述2個函數不是C标準庫的成員,可以用sprintf()代替它們以提高相容性
(3)生成随機數:
生成1個屬于[0,RAND_MAX]的随機數:int rand();
//實際是利用算法(如線性同餘法)生成的僞随機數,在一定範圍内可看成随機數
//生成随機數有多種算法,ANSI C允許C實作針對特定機器使用最佳算法,但也提供了可移植的标準算法
//C11規定RAND_MAX至少為32767,該宏定義在stdlib.h中
//每次運作程式,如果種子不變,則第n個rand()生成的數都是相同的,這是由于随機數生成算法是不變的
//執行個體1:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("%d",RAND_MAX);//結果:32767
return 0;
}
//執行個體2:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i;
for (i=0;i<10;i++) {
printf("%d\n",rand());
}
return 0;
}
//結果:
41
18467
6334
26500
19169
15724
11478
29358
26962
24464
//執行個體3:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i;
for (i=0;i<5;i++) {
printf("%d\n",rand()%100);
//生成1個屬于[0,100)的随機數
}
return 0;
}
//結果:
41
67
34
0
69
//#######################################################################################
為rand()設定随機數種子:void srand(<seed>);
//rand()以随機數種子為基準,通過遞推公式推出一系列數,當這些數很多時,就符合正态公布,進而相當于産生了随機數
//如果沒有手動設定随機數種子,調用rand()時會自動将随機數種子設為1
//參數說明:
seed:提供1個種子值;為unsigned int
//經常為(unsigned int)time(0)/(unsigned int)geypid(0)
//執行個體:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
srand(0);
printf("%d",rand());//結果:38
return 0;
}
//#######################################################################################
//1種實作:将2個檔案一起編譯
//函數定義.c:
static unsigned long int next=1;//種子
int rand1(void) {
next=next*1103515245+12345;
return (unsigned int)(next/65535)%32768;
}
void srand1(unsigned int seed) {
next=seed;
}
//調用.c:
#include <stdio.h>
extern void srand1(unsigned int seed);
extern int rand1(void);
int main(void) {
int count;
unsigned seed;
printf("Please enter your choice of seed:");
while (scanf("%u",&seed)==1) {
srand1(seed);
for (count=0;count<5;count++) {
printf("%d\n",rand1());
}
printf("Please enter next seed (q to quit):");
}
return 0;
}
//結果:
Please enter your choice of seed:2
909
22817
10240
12914
25838
Please enter next seed (q to quit):3
17747
7108
10365
8313
20623
Please enter next seed (q to quit):2
909
22817
10240
12914
25838
Please enter next seed (q to quit):q
(4)結束程式:
參見:https://blog.csdn.net/weixin_43520054/article/details/94392365
https://blog.csdn.net/wy1550365215/article/details/70216750
關閉所有打開的檔案并結束目前程式:int <ecode>=exit(int status);
//main()傳回系統時會自動調用exit()
//參數說明:
status:表示程式是正常退出(為0)還是異常退出(為非零值,不同的值用于區分不同錯誤)
//也可以分别使用EXIT_SUCCESS/EXIT_FAILURE,這樣可移植性更好.這2個宏也定義在stdlib.h中
//傳回值也是status;在有多個程序時,如果要檢測上個程序是否正常退出的,就要用到傳回值
//注意:不同作業系統能識别的傳回值的通路不同,但C标準規定了1個最小的範圍,尤其是0表示正常退出
//執行個體:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("AAA\n");
exit(EXIT_SUCCESS);
printf("BBB");
return 0;
}
//結果:
AAA
//####################################################################################################################
注冊退出程式時要調用的函數:int atexit(void (*func)(void));
//這些函數稱為"登記函數";1個函數被注冊幾遍就會被執行幾遍;ANSI C保證至少可以注冊32個函數
//調用exit()時會執行注冊了的函數,執行順序與注冊順序相反,即後注冊的先執行
//參數說明:
func:指定要注冊的函數;為函數指針(如函數名)
//該函數應不帶任何參數且傳回void,通常用于執行一些清理任務(更新監視程式的檔案,重置環境變量...)
//執行個體:
#include <stdio.h>
#include <stdlib.h>
void f(void) {
printf("Exit Exit Exit\n");
}
int main(void) {
atexit(f);
printf("AAA\n");
atexit(f);
printf("BBB\n");
return 0;
}
//結果:
AAA
BBB
Exit Exit Exit
Exit Exit Exit
//####################################################################################################################
abort();
- exit()與return語句:
根據ANSI C的規定,在最初調用的main()中調用exit()與使用return語句的效果相同,如:
return 0;
相當于:
exit(0);
但如果不是在最初調用的main()中,如在1個遞歸調用main()的程式中或在其他函數中,return
語句隻會把控制權交給上1級調用,而exit()仍會終止程式
- 退出程式的順序:
調用exit()→由exit()執行"登記函數"→由exit()完成清理工作(重新整理所有輸出流,關閉所有打開的流,關閉由tmpfile()建立的臨時檔案)→exit()把
控制權傳回主機環境并報告終止狀态(如果可能的話)
(5)排序:
進行快速排序:void qsort(void * base,size_t nmemb,size_t size,int (*compar)(const void * p,const void * q));
//參數說明:
base:指定指向要排序的數組首元素的指針(如<avar>,&<avar>[0])
//可以是任何類型的數組,因為ANSI C允許把任何類型的指針強制轉換為指向void的指針
nmemb:指定待排序項的數量
size:指定每個元素的大小(機關為B)
compar:指定1個函數指針,該函數用于确定排序的順序
//該函數的參數為2個指向待比較的項的指針
//若傳回1,則将p放到q前面;若傳回-1,則将q放到p前面;若傳回0,則p/q的順序不确定
//執行個體:
#include <stdio.h>
#include <stdlib.h>
int f(const void * p1,const void * p2) {
const double * a=(const double *)p1;
const double * b=(const double *)p2;
if ((*a)>(*b)) {//此時将從小到大排序
return 1;
} else if ((*a)<(*b)) {
return -1;
} else if ((*a)==(*b)) {
return 0;
}
//if ((*a)>(*b)) {//此時将從大到小排序
// return -1;
//} else if ((*a)<(*b)) {
// return 1;
//} else if ((*a)==(*b)) {
// return 0;
//}
}
int main(void) {
double arr[20]={3,6,1,14,0,32,1,45,9,22,45,6,10,94,34,2,44,19,3,65};
qsort(arr,20,sizeof(double),f);
int i;
for (i=0;i<20;i++) {
printf("%f ",arr[i]);
}
return 0;
}
//結果:
0.000000 1.000000 1.000000 2.000000 3.000000 3.000000 6.000000 6.000000 9.000000 10.000000 14.000000 19.000000 22.000000 32.000000 34.000000 44.000000 45.000000 45.000000 65.000000 94.000000
(6)查找:
進行二分查找:void * r=bsearch(const void * key,const void * base,size_t nitems,size_t size,int (* compar)(const void *,const void *));
//參數說明:其他參數同qsort()
key:指定指向要查找的值的指針
nitems:指定數組元素數
r:傳回查找結果
//如果查找成功,則傳回指向數組中指定元素的指針;否則,傳回空指針
//執行個體:
#include <stdio.h>
#include <stdlib.h>
int values[]={5,20,29,32,63};
int cmp(const void * a, const void * b) {
return *(int *)a-*(int *)b;
}
int main () {
int * item;
int key=32;
item=(int *)bsearch(&key,values,5,sizeof(int),cmp);
if(item!=NULL) {
printf("Found item = %d\n", *item);
}
else {
printf("Item = %d could not be found\n", *item);
}
return(0);
}
//結果:
Found item = 32
2.malloc.h庫
使用下述指令也可:
#include <stdlib.h>
可簡單認為stdlib.h包含malloc.h
ANSI C建議使用stdlib.h,但許多C編譯要求使用malloc.h
(1)malloc():
功能:請求作業系統配置設定記憶體
詳情參見 動态記憶體配置設定.三.1 部分
(2)free():
功能:釋放記憶體
詳情參見 動态記憶體配置設定.三.2 部分
(3)calloc():
請求作業系統配置設定多個記憶體單元:void * calloc(size_t <num>,size_t <big>);
//size_t通常是unsigned int
//在ANSI C之前傳回char*,ANSI C規定傳回void*
//參數說明:
num:指定需要的存儲單元的個數
big:指定每個存儲單元占用的位元組數
請求配置設定多個記憶體單元并強制轉換:<type> * <var>=(<type> *)calloc();
//參數說明:
type:要轉換成的資料類型
//執行個體:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
long * newmem;
newmem=(long *)calloc(100,sizeof(long));
printf("%d",*(newmem+2));//結果:0
//所有元素都會被自動初始化為0/' '
return 0;
}
五.其他
1.斷言庫assert.h:
assert.h是1個用于輔助調試程式的小型庫,由assert()宏構成,接受1個整型表達式作為參數.如果表達式為假,就在stderr中寫入1條錯誤資訊,并
調用stdlib.h中的abort()終止程式:
#include <stdio.h>
#include <assert.h>
#include <math.h>
int main(void) {
double x, y, z;
printf("Enter 2 numbers (use \",\" to seperate,first one must be bigger than second one):");
while (scanf("%lf,%lf", &x, &y) == 2) {
printf("You enter %lf and %lf\n", x, y);
fflush(stdin);
z = x * x - y * y;
assert(z >= 0);
printf("The answer is %lf\n", sqrt(z));
printf("Enter 2 numbers (use \",\" to seperate,first one must be bigger than second one):");
}
return 0;
}
//結果:
Enter 2 numbers (use "," to seperate,first one must be bigger than second one):4,3
You enter 4.000000 and 3.000000
The answer is 2.645751
Enter 2 numbers (use "," to seperate,first one must be bigger than second one):1,2
You enter 1.000000 and 2.000000
Assertion failed!//具體的錯誤資訊由編譯器決定(這裡是TDM-GCC 4.9.2 64-bit Release)
Program: E:\Program\C_C++\1.exe//程式
File: E:\Program\C_C++\1.c, Line 12//源代碼檔案
Expression: z >= 0//為false的表達式
使用if語句也可以實作類似的效果.但assert()宏有幾個優點:
①可以自動識别出現問題的檔案/行号/表達式
②調試完畢時,在包含assert.h前加入以下代碼:
#define NDEBUG
即可禁用所有assert()宏.如果需要再次調試,隻需去除上述代碼以重新啟用assert()宏
//####################################################################################################################
C11新增了_Static_assert聲明._Static_assert()接受2個參數,第1個參數是1個整型常量表達式(不能包含變量),第2個參數是1個字元串.若第
1個表達式為假,程式會無法通過編譯,并且編譯器會顯示第2個參數:
#include <stdio.h>
#include <assert.h>
#define SA 333
//_Static_assert(SA/111-3,"wrong1");
int main(void) {
_Static_assert(SA/111-3,"wrong2");
return 0;
}
//報錯:
//[Error] static assertion failed: "wrong1"
[Error] static assertion failed: "wrong2"
使用_Static_assert聲明可以提高調試效率,因為無需編譯完成并運作程式
2.時間庫time.h
(1)time():
傳回時間:time_t time(<n>);
//time_t定義在
//參數說明:
n:
3.可變參數庫stdarg.h:
該庫提供1個類似于變參宏的功能,用于使函數接受數量可變的參數