C语言基础 库函数

一.访问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π/4long 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个类似于变参宏的功能,用于使函数接受数量可变的参数
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值