18 函数
18.1 时间相关的函数
头文件
#include<time.h>
18.1.1 time()
time_t time(time_t *t)
返回的值是从1970年1月1日00:00:00到当前时刻的时长,时长单位是秒。
time_t curr_time;
time(&curr_time);
printf("%lld",curr_time);
time_t是一个整数类型(int或者long或long )
18.1.2 ctime()
char *ctime(const time_t *timer)
将时间值转换为字符串并返回
time_t curr_time;
time(&curr_time);
printf("%lld",ctime(&curr_time));
18.1.3 difftime()
double difftime(time_t time1,time_t time2);
返回time1和time2之间相差的秒数。
18.2 数学相关的函数
头文件
#include<math.h>
返回的都是double类型的
函数名 | 描述 |
---|---|
sqtr(x) | 平方根 |
cbrt(x) | 立方根 |
pow(x,y) | x的y次方 |
fabs(x) | x的绝对值 |
ceil(x) | 向上取整 |
floor(x) | 向下取整 |
round(x) | 四舍五入取整 |
trunc© | 截断小数部分 |
18.3 内存管理相关的函数
18.3.1 C程序的内存分配
C程序中,不同数据在内存中分配说明:
-
全局变量和静态局部变量——内存中的静态存储区/全局区
-
非静态的局部变量——内存中的动态存储区:stack 栈
-
临时使用的数据——建立动态内存分配区域,需要时随时开辟,不需要时及时释放——heap 堆
-
根据需要 向系统申请 所需大小的空间,由于未在声明部分定义其为变量或者数组,不能通过变量名或者数组名来引用这些数据,只能通过指针来引用)
动态内存分配指根据需要向系统申请所需大小的空间,由于未在声明部分定义其为变量或者数组,不能通过变量名或者数组名来引用这些数据,只能通过指针来引用)
18.3.2 void指针
它可以指向任何类型的数据。
void指针与其他所有类型指针之间是相互转换的关系,任何一类型的指针都可以转换成为void指针,而void指针也可也转换为任意类型的指针。
由于不知道void指针指向什么类型,所以不能用*运算符去除它指向的值(解引用)。
18.3.3 内存动态分配函数
头文件
<stdlib.h>
void *malloc(unsigned int size);
在内存的 动态存储区(堆区) 中分配一个 长度为size 的 连续空间 。并将该空间的首地址作为函数值返回,即此函数是一个指针函数。
malloc()分配内失败时会返回NULL,NULL的值是0,是一个无法读写的内存地址,可以理解成一个不指向任何地方的指针
int *p = malloc(sizeof(int));
if(p == NULL){
//分配失败
}
18.3.4 了解calloc()
void *calloc(unsigned int n,unsigned int size)
在内存的动态存储区(堆区)中分配n个,单位长度为size的连续空间,这个空间一般比较大,总共占用n*size 个字节。并将该空间的首地址作为函数的返回值。如果函数没有成功执行,返回NULL。
calloc()函数适合为 一维数组 开辟动态存储空间,n为数组元素个数,每个元素长度为size。
18.3.5 了解realloc()
void *realloc(void *p,unsigned int size)
重新分配malloc()或calloc()函数获得的动态空间大小,即调整大小的内存空间。将先前开辟的内存块的指针p指向的动态空间大小改变为size,单位字节。返回值是一个全新的地址(数据也会自动复制过去),也可能返回跟原来一样的地址。分配失败返回NULL。
realloc() 优先在原有内存块上进行缩减,尽量不移动数据,所以通常是返回原先的地址。
如果新内存块小于原来的大小,则丢弃超出的部分;如果大于原来的大小,则不对新增的部分进行初始化(程序员可以自动调用memset() )。
int *b;
b = (int *)malloc(sizeof(int) * 10);
b = (int *)realloc(b,sizeof(int) * 2000);
18.3.6 掌握free()
void free(void *p);
释放指针变量p所指向的内存空间,使这部分内存能重新被其它变量使用。否则这个内存块会一直占用到程序运行结束。
注意:
1.指针p必须是经过动态分配函数malloc成功后返回的首地址
2.分配的内存块一旦释放,就不应该再次操作已经释放的地址,也不应该再次使用free()对该地址释放第二次。
3.如果忘记调用free()函数,同时p所在的函数调用结束后p指针已经消失了,导致无法访问未回收的内存块,构成内存泄漏。
**内存泄露 memory leak,**是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
18.3.7 内存分配的基本原则
(1)**避免分配大量的小内存块。**分配堆上的内存有一些系统开销,所以分配许多小的内存块比分配几个大内存块的系统开销大。
(2)**仅在需要时分配内存。**只要使用完堆上的内存块,就需要及时释它,否则可能出现内存泄漏。
(3)**总是确保释放已分配的内存。**在编写分配内存的代码时,就要确定好在代码的什么地方释放内存。