天天看點

C語言基礎 庫函數

一.通路C庫

如何通路C庫取決于實作,下面是一些可能的方法
           

1.自動通路:

C語言基礎 庫函數

2.檔案包含:

C語言基礎 庫函數

3.庫包含:

C語言基礎 庫函數

二.數學庫

以下涉及的角度均為弧度制
           

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個類似于變參宏的功能,用于使函數接受數量可變的參數
           

繼續閱讀