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语言三剑客 文章被收录于专栏

“C语言三剑客”的相关扩展、思考、提纲 2020年10月开始更新《C缺陷与陷阱》

全部评论

相关推荐

02-12 00:59
已编辑
哈尔滨工业大学 产品经理
华为 软件开发岗 20.6*16薪 本科
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务