zl程序教程

您现在的位置是:首页 >  IT要闻

当前栏目

C语言:常用函数

2023-02-18 16:40:17 时间

这是很基础的教程,我只是写给自己看,作为一个学习笔记记录一下,如果正在阅读的你觉得简单,请不要批评,可以关掉选择离开

如何学好一门编程语言

  • 掌握基础知识,为将来进一步学习打下良好的基础。
  • 上机实践,通过大量的例题学习怎么设计算法,培养解题思路。
  • 养成良好的编码习惯,注释一定要写,要不然保你一周后自己写的代码都不认识了

   像 stdio.h 这样经常使用的标准库就不介绍了

随机数

#include <stdlib.h>
int rand (void);

  rand() 会随机生成一个位于 0 ~ RAND_MAX 之间的整数。RAND_MAX 是 <stdlib.h> 头文件中的一个宏,它用来指明 rand() 所能返回的随机数的最大值 32767。

#include <stdio.h>
#include <stdlib.h>

int main(){
    int a = rand();
    printf("%d\n",a);    // 193
    return 0;
}

设置随机数种子

  但是,我们每次运行上面的代码生成的随机数都一样,虽然随机数种子在每次启动计算机时是随机的,但是一旦计算机启动以后它就不再变化了;也就是说,每次启动计算机以后,种子就是定值了,所以生成的随机数就是固定的。通过 srand() 函数来重新“播种”,这样种子就会发生改变。

void srand (unsigned int seed);

它需要一个 unsigned int 类型的参数。在实际开发中,我们可以用时间作为参数,只要每次播种的时间不同,那么生成的种子就不同,最终的随机数也就不同。

  使用 <time.h> 头文件中的 time() 函数即可得到当前的时间(精确到秒),就像下面这样:

srand((unsigned)time(NULL));

对上面的代码进行修改,生成随机数之前先进行播种:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
    int a;
    srand((unsigned)time(NULL));
    a = rand();
    printf("%d\n", a);
    return 0;
}

生成一定范围内的随机数

利用取模的方法产生一定范围的随机数

int a = rand() % 10;    //产生0~9的随机数,注意10会被整除

如果要规定上下限:

int a = rand() % 51 + 13;    //产生13~63的随机数

分析:取模即取余, rand()%51+13 我们可以看成两部分, rand()%51 是产生0~50之间的随机数,后面+13保证 a 最小只能是 13,最大就是 50+13=63。

连续生成随机数

有时候我们需要一组随机数(多个随机数),该怎么生成呢?很容易想到的一种解决方案是使用循环,每次循环都重新播种,请看下面的代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
    int a, i;
    //使用for循环生成10个随机数
    for (i = 0; i < 10; i++) {
        srand((unsigned)time(NULL));
        a = rand();
        printf("%d ", a);    // 8 8 8 8 8 8 8 8 8 8
    }
    return 0;
}

运行结果非常奇怪,每次循环我们都重新播种了呀,为什么生成的随机数都一样呢?

这是因为,for 循环运行速度非常快,在一秒之内就运行完成了,而 time() 函数得到的时间只能精确到秒,所以每次循环得到的时间都是一样的,这样一来,种子也就是一样的,随机数也就一样了。

那么,该如何解决呢?

计时功能

  在 Linux/Unix 环境下,计算 C 程序运行时间可以通过time.h头文件中以下三个函数来实现: clock() 、 time() 、 gettimeofday() 。

clock()函数

   clock() 函数返回的是时钟计时单元数(俗称硬件滴答数),要换算成秒或者毫秒,需要用到 CLOCKS_PER_SEC 常量(或者CLK_TCK常量,两者其实一样),该常量表示一秒钟会有多少个时钟计时单元。

#include <time.h>
#include <stdio.h>

int main(){
    clock_t start, finish;
    double duration;
    long i = 100000000;

    start = clock();    // 开始计数
    while (i--);        // 处理函数
    finish = clock();   // 结束计数
    duration = (double)(finish-start)/CLOCKS_PER_SEC;
    printf("%f seconds\n", duration);   // 0.125000 seconds

    return 0;
}

注意事项:

  1. 它返回的是 CPU 耗费在本程序上的时间。也就是说,途中 sleep 的话,由于 CPU 资源被释放,那段时间将不被计算在内。因此,若函数中存在sleep()函数,则sleep()函数消耗的时间将不包含在内;
  2. 这个函数的精度不适很高,大约10ms,低精度的程序全部输出 0ms。像计算printf()之类的调用时间是不可能实现的,因为printf()的速度太快了,基本上和clock()的速度一样。所以,此函数适合用于计算一些大型程序,或循环程序。
  3. 如果超过一个小时,将要导致溢出
  4. 函数clock没有考虑CPU被子进程使用的情况
  5. 也不能区分用户空间和内核空间
  6. 所以clock函数在linux系统上变得没有意义

time()函数

  time()函数返回当前日历时间。就是用“从一个标准时间点(一般是1970年1月1日0时0分0秒)到当今时间经过的秒数”来表示的时间。其原型为:

time_t time(time_t * timer); 

如果参数为空(NULL),函数将返回现在的日历时间,比如下面这个例子用来显示当前的日历时间:

#include <time.h>
#include <stdio.h>

int main(){
    time_t t;
    t=time(NULL);
    printf("1970年1月1日以来的秒数: %ld",t);    // 1634915031

    return 0;
}

也可以利用time()函数计算某段程序的运行时间:

#include <time.h>
#include <stdio.h>
#include <unistd.h>

int main(){
    time_t t1,t2;
    time(&t1);
    //此处放置要测试的代码
    sleep(1);//延时 1 秒
    time(&t2);
    printf("本程序运行时间: %d",t2-t1);    // 1

    return 0;
}

gettimeofday() 函数

gettimeofday()的函数原型为:

#include <sys/time.h>
int gettimeofday(struct timeval*tv, struct timezone *tz )

gettimeofday()会把目前的时间用 tv 结构体返回,当地时区的信息则放到 tz 所指的结构中。其结构体定义为:

struct timeval {
    long tv_sec;/**/
    long tv_usec;/*微妙*/
};

struct timezone {
    int tz_minuteswest;/*和greenwich 时间差了多少分钟*/
    int tz_dsttime;/*type of DST correction*/
};

gettimeofday()函数中 tv 或者 tz 都可以为空。如果为空则就不返回其对应的结构体。函数执行成功后返回 0,失败后返回 -1,错误代码存于 errno 中。

#include <sys/time.h>
#include <stdio.h>


int main() {
    struct timeval tv;
    struct timezone tz;

    gettimeofday(&tv, &tz);

    printf("tv_sec:%ld\n",tv.tv_sec);       // 1634915650
    printf("tv_usec:%ld\n",tv.tv_usec);     // 848136
    printf("tz_minuteswest:%d\n",tz.tz_minuteswest);
    printf("tz_dsttime:%d\n",tz.tz_dsttime);
    return 0;
}

在使用gettimeofday()函数时,第二个参数一般都为空,因为我们一般都只是为了获得当前时间,而不用获得 timezone 的数值。

  也可利用此函数计算某段程序的运行时间:

#include <sys/time.h>
#include <stdio.h>


int main() {
    struct timeval start;
    struct timeval end;
    unsigned long timer;

    gettimeofday(&start, NULL);
    printf("hello world!\n");
    gettimeofday(&end, NULL);
    timer = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
    printf("timer = %ld us\n", timer);  // timer = 328 us
    return 0;
}

gettimeofday()函数的计算精度为微秒,精度已经很高了。

综上所述,gettimeofday()函数的精度最高,为微秒级别;clock()函数的精度次之,为 10ms 级别;time()函数的精度最低,为 1s 级别。

其他

整数转字符串

#include <stdio.h>

char *Int2String(int num, char *str) {
    //指示填充str
    int i = 0;
    //如果num为负数,将num变正
    if (num < 0) {
        num = -num;
        str[i++] = '-';
    }
    //转换
    do {
        str[i++] = num % 10 + 48;//取num最低位 字符0~9的ASCII码是48~57;简单来说数字0+48=48,ASCII码对应字符'0'
        num /= 10;//去掉最低位
    } while (num);//num不为0继续循环

    str[i] = '\0';

    //确定开始调整的位置
    int j = 0;
    //如果有负号,负号不用调整
    if (str[0] == '-') {
        j = 1;//从第二位开始调整
        ++i;//由于有负号,所以交换的对称轴也要后移1位
    }
    //对称交换
    for (; j < i / 2; j++) {
        //对称交换两端的值 其实就是省下中间变量交换a+b的值:a=a+b;b=a-b;a=a-b;
        str[j] = str[j] + str[i - 1 - j];
        str[i - 1 - j] = str[j] - str[i - 1 - j];
        str[j] = str[j] - str[i - 1 - j];
    }

    return str;
}


int main() {
    int number1 = 0xac2031;
    int number2 = -123456;
    char string[16] = {0};
    Int2String(number1, string);
    printf("数字:%d 转换后的字符串为:%s\n", number1, string);
    // 数字:11280433 转换后的字符串为:11280433
    Int2String(number2, string);
    printf("数字:%d 转换后的字符串为:%s\n", number2, string);
    // 数字:-123456 转换后的字符串为:-123456
    return 0;
}
View Code

pcm拼接

#include <stdio.h>
#include <string.h>


int main(int arvc, char *argv[]) {
    FILE *wavtxt;
    FILE *pcmfile;
    FILE *wavfile;
    unsigned long read_len;
    char base[1000]={0};
    char *buf[1024];

    wavtxt = fopen("../wavlist.txt", "r");
    if (wavtxt == NULL) {
        printf("!Error: Can't open wavlist.txt.\n");
        return 1;
    }

    pcmfile = fopen("../clear.pcm", "wb");
    if (pcmfile == NULL) {
        printf("!Error: Can't open clear.pcm.\n");
        return 1;
    }
    // feof() 判断指针是否已经到达文件尾部的
    while (!feof(wavtxt)) {
        fscanf(wavtxt,"%s\n",base);

        printf("%s\n", base);

        wavfile = fopen(base, "rb");
        if (wavfile == NULL) {
            printf("!Error: Can't open %s.\n", base);
            return 1;
        }

        fseek(wavfile, 44, SEEK_SET);        // 将文件指针移动到文件开头,后移44字节

        while ((read_len = fread(buf, 1, sizeof(buf), wavfile)) != 0) {
            fwrite(buf, 1, read_len, pcmfile);
        }

        fclose(wavfile);
    }

    fclose(wavtxt);
    fclose(pcmfile);
}
View Code

 

 

 

参考

C语言中文网:C语言随机数生成教程

Linux/Unix 环境下实现精确计算程序运行的时间

Linux下时间机制 

C 语言整数与字符串的相互转换