C和指针『临时笔记』
C和指针——标准函数库
2020-12-15 08:00:01
C语言标准函数库
C和指针——标准函数库
本文所有测试环境:
编译器:DevC++5.9.2(GCC4.8.1)
一、纯C语言中,区分abs,labs,fabs
问题症状:以前或许对于abs和fabs哪个是针对int,哪个针对double有时弄混
int abs( int value );//<stdlib.h> long int labs( long int value );//<stdlib.h> double fabs( double x );//<math.h>
现在对比“函数原型”记忆:
abs是absolute单词首部,然后编译器默认很多数字是int,所以应对int的绝对值是abs
针对long的绝对值是l+abs,对于fabs为啥是f开头,是针对double不是float?原因,,主要我目前也没有找到专门对付float的绝对值的库函数啊。而double范围更大,就忍忍用着吧。
二、c++中关于abs的重载
int abs ( int n );//C++98 long int abs ( long int n );//C++98 long long int abs (long long int n );//C++11,注意!
三、<stdlib.h>
(1)算术
div_t div( int numerator , int denominator );//numerator(分数中的)分子,denominator分母,分子除分母 ldiv_t ldiv( int int number, long int denom );//是div的针对long的版本
div的源码解读(ldiv_t请类推)
1、返回的div_t结构体中有两个成员(顺序不一定如下!)PS:div_t
可以直接使用,看代码测试
int quot;//商 int rem;//余数
2、返回的结构体为什么取名叫这个?
div简洁易懂,然后t表示temp,临时的意思,然后中间有下划线(或许可以解释为什么纯C的软件工程师为什么用“下划线”命名法)
3、测试代码
#include<stdlib.h> #include<stdio.h> int main() { div_t solve;//直接使用 solve=div(5,2);//这里涉及另一个知识点:结构体的复制 printf("%d %d\n",solve.quot , solve.rem);//C语言中5/2=2 5%2=1 return 0; } //输出 //2 1
/号的细节
/操作符的除法运算结果并未精确定义!
如果不能整除,商将是所有小于代数商的整数中最靠近它的那个整数。
编译器相关:当/
操作符的任何一个操作数为负而不能整除时,到底商是最大的那个<=
代数商的整数还是最小的那个>=
代数商的整数,这取决于编译器。(没理解透彻这个,希望有牛油能帮忙理解这句中文。。)
#include<stdlib.h> #include<stdio.h> int main() { div_t solve; solve=div(-5,2);//负数 printf("%d %d\n",solve.quot , solve.rem); return 0; } //输出和我们数学上的没区别,然后,关于“代数商”,应该指的是我们纯数学上的商 //-2 -1
(2)随机数
重要程度:
- 个人学科背景:我在进行“材料模拟计算”中会需要弄到“蒙特卡洛”,需要熟练这个里面的函数
- CSP/PAT等编码中需要用到PAT
- 秋招的时候,如果不是C++选手,关于手撕代码的时候,如果输入随机的数字啥的
- (反正就是很重要)
int rand(void);//返回一个0-RAND_MAX的伪随机数,PS:那个RAND_MAX宏可以直接使用,就像INT_MAX一样 void srand( unsigned int seed );
1、srand播种作用的理解:初始化“随机数发生器”,伪随机数生成器使用作为种子传递的参数初始化。对于srand调用中使用的每个不同的种子值,伪随机数生成器可能会在后续的rand调用中生成不同的连续结果(这就是我们平时所说的“随机数种子”播种的意义所在)。使用相同种子的两个不同初始化将在后续对rand的调用中生成相同的连续结果。如果seed设置为1,则生成器将重新初始化为其初始值,并生成与调用rand或srand之前相同的值。为了生成类似随机的数字,srand通常被初始化为一些独特的运行时值,比如函数time返回的值。这对于大多数琐碎的随机化需求来说已经足够独特了。
2、rand函数作用理解:一次次,返回某个种子导致的“随机数发生器”生成的系列结果中的数值。
随机数的编程技巧
请先学后面的time.h中的time函数,显然随着时间的推移,time返回的数值一直是变化的(是不是顺路也知道,time的返回值time_t或许是个unsigned int呢?)
书中代码测试:
实现了类似C++的STL中random_shuffle的部分类似功能,当前两者有区别
#include<stdlib.h> #include<stdio.h> #include<time.h> #define TRUE 1 #define FALSE 0 int solve[10]; void shuffle( int * deck, int n_cards ) { static int first_time=TRUE; if( first_time ) { first_time=FALSE; srand( (unsigned int)time(NULL) ); } int i; for(i=n_cards-1 ; i>0 ; --i) { int where; int temp; where=rand()%i; temp=deck[ where ]; deck[ where ]=deck[ i ]; deck[ i ]=temp; } } int main() { int i=0; for(i=0; i<10; ++i) { solve[i]=i; } shuffle( solve, 10); for(i=0; i<10; ++i) { printf("%d\n",solve[i]); } return 0; } //某次随机输出 5 0 3 1 7 9 8 6 2 4
(3)字符串转换(重要!!!)
int atoi( char const * string) long int atol( char const * string) long int strtol( char const * string, char ** unused, int base );//注意,这个地方有个二级指针做输出的典型用法,输出给一级指针,详细见代码 unsigned long int strtoul( char const * string, char ** unused, int base );
代码测试
/* strtol example */ #include <stdio.h> /* printf */ #include <stdlib.h> /* strtol */ int main () { char szNumbers[] = "2001 60c0c0 -1101110100110100100000 0x6fffff"; char * pEnd; long int li1, li2, li3, li4; li1 = strtol (szNumbers,&pEnd,10);//pEnd感觉是用来接力的,二级指针做输 li2 = strtol (pEnd,&pEnd,16); li3 = strtol (pEnd,&pEnd,2); li4 = strtol (pEnd,NULL,0); printf ("The decimal equivalents are: %ld.\n", li1);//Dec 2001 Dec 2001 printf ("The decimal equivalents are: %ld.\n", li2);//Hex 60c0c0 Dec printf ("The decimal equivalents are: %ld.\n", li3);//Binary -1101110100110100100000 Dec printf ("The decimal equivalents are: %ld.\n", li4); return 0; } //输出 The decimal equivalents are: 2001. The decimal equivalents are: 6340800. The decimal equivalents are: -3624224. The decimal equivalents are: 7340031.
五、日期和时间函数<time.h>
(1)clock处理器滴答
clock_t clock( void );//返回从程序开始执行起处理器所消耗的时间。
注意:
1、这个值可能是近似值,如果需要更精确的值,你可以在main函数刚开始和以后调用clock求差值。
(这个编程技巧,通常用作“OJ使用初学者”判定自己程序会不会超时,Tips:小声告诉你,这个方法有效,但没必要,一般代码1s,最长的就算是5s还是15s,你自己用最耗时的边界数据测一下,心中看程序跑多久出来就好了,不要因为写程序写多了,感觉好像什么都要用解决似的,那样就掉进了纯程序的视角)
2、如果机器无法提供“处理器时间”,或者如果时间值太大,无法用clock_t变量表示,函数就返回-1
3、clock_t 是整数数字,通常它是处理器时钟滴答的次数
4、编程技巧:如果相关clock转换为秒,请记住这个宏CLOCKS_PER_SEC
,使用如下
- 观察,是不是和DevC++每次运行后,告诉你的进程过了多久有点像???
/* clock example: frequency of primes */ #include <stdio.h> /* printf */ #include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */ #include <math.h> /* sqrt */ int frequency_of_primes (int n) { int i,j; int freq=n-1; for (i=2; i<=n; ++i) for (j=sqrt(i);j>1;--j) if (i%j==0) {--freq; break;} return freq; } int main () { clock_t t; int f; t = clock(); printf ("Calculating...\n"); f = frequency_of_primes (99999); printf ("The number of primes lower than 100,000 is: %d\n",f); t = clock() - t; printf ("It took me %d clicks (%f seconds).\n",t,((float)t)/CLOCKS_PER_SEC); return 0; } //输出,上面程序来自cplusplus.com是计算小于100,000的质数 //Calculating... //The number of primes lower than 100,000 is: 9592 //It took me 38 clicks (0.038000 seconds).
5、宏的来源clocks,per每次,sec是seconds的首部
(2)time函数
time_t time( time_t * returned_value );//返回的是当前的日期和时间
我们发现,形式参数和返回值都是time_t类型
1、形参的作用:如果参数是个非NULL的指针,时间值也将通过这个指针进行存储(很显然,这个没有经过const修饰,一个很典型的二级指针传出参数的写法)
2、返回值:如果机器无法提供当前的日期和时间,或者时间值太大,无法用time_t变量表示,函数就返回-1
3、注意:标准并未要求这个函数的结果值用秒(s)来表示,(???那time_t是什么类型呢?)
(3)ctime和difftime
char * ctime( time_t const * time_value );//将time_t类型的数据,转换为字符型,就可以打印日期和时间了 double difftime( time_t time1, time_t time2 );//计算rime1-time2的差,并且转换为秒(s)
测试代码
#include<stdlib.h> #include<stdio.h> #include<time.h> int main() { time_t begin=time(0); char solve[30]; char *p=solve; p=ctime( &begin ); printf("%s\n",p); int loop=INT_MAX; while( loop-- ) { } time_t end=time(0); printf("%lfseconds\n", difftime( end, begin) ); return 0; } //输出 //Mon Dec 14 14:31:06 2020 // //3.000000seconds //
“C语言三剑客”的相关扩展、思考、提纲 2020年10月开始更新《C缺陷与陷阱》