一.访问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个类似于变参宏的功能,用于使函数接受数量可变的参数