目录
malloc:
参数指定要分配的字节数,如果成功,返回堆上分配的内存的指针,如果失败,返回NULL;内存不会被修改或清空
函数原型:void* malloc(size_t)
calloc:
在分配的同时清空内存为0,
函数原型:void * calloc(size_t numElements,size_t elementSize);
根据元素个数和每个元素占用内存的乘积分配内存
例如:
int *pi = (int *)calloc(5,sizeof(int));
等价于
int *pi = (int*)malloc(sizeof(int)*5);
memset(pi,0,sizeof(int)*5);
memset
void * memset(void *s,int c,size_t n)
memset会使用某个值填充内存,第一个参数是要填充的起始地址,第二个参数是要填充的内容,第三个参数填充的字节数
calloc可以能malloc慢。
memset函数返回值意义:
刚突然想到一个问题,menset返回值就是第一个参数,它的返回值为什么不设为void,有什么意义了,知道我看了这个例子惨恍然大悟:
char a[200];
strcpy(memset(a, 0, 200), "bla");
memset容易出错的地方:
memset中初始化数据的时候,是逐字节初始化的。例如:想利用memset把一些整型数据初始化为1时,会出bug。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
int *b=(int *)malloc(sizeof(int)*10);
memset(b,1,sizeof(int)*10);
printf("%d\n",b[0]);//16843009
return 0;
}
上面结果为16843009,二进制为00000001 00000001 00000001 00000001。它不是把一个int初始为1,而是把每个字节初始化为1。
参考讨论:https://bbs.csdn.net/topics/370127517
那要是填充的内容大于255,岂不是越界了?
realloc:
改变分配的内存的大小
函数原型:void* realloc(void *ptr,size_t size)
返回指向内存块的指针
第一个参数是指向原内存块的指针,第二个是重新分配的内存的大小
如果size比原来分配的内存小,那么多余的内存会还给堆,不能保证多余的内存被清空;
如果比原来分配的大,可能的话,就在紧挨着当前分配的内存后面分配新的内存,否则就在堆得其他区域分配内存,并把旧的内存复制到新区域。
关于重新分配的内存空间比原来内存空间小的问题:
看个例子,
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(void)
{
char *string1;
char *string2;
string1 = (char*)malloc(16);
strcpy(string1,"0123456789AB");
string2 = realloc(string1,8);
printf("string1 value:%p [%s]\n",string1,string1);
printf("string2 value:%p [%s]\n",string2,string2);
return 0;
}
输出结果类似下图:string1还是指向原来的地址,多余的空间的内容没有被修改,还是把原来的内容全部给输出来了。
但是,调整后只分配了8个字节内存地址,程序实际使用的内存超出分配的内存,不是一个好做法。最简单的方法就是把NUL赋值给地址507。(C语言中没有NUL的宏定义,如果要是用NUL,就自己#define NUL '\0',还是#define NUL ('\0'),不加括号有没有影响?)
free:
free不能从中间释放内存,例如
int *p=(int*)malloc(sizeof(int)*10);
不能free(p+5),从中间释放部分能存;只能free(p)。
内存泄漏:
已经分配的内存以后不再使用时,没有释放,就会造成内存泄漏。内存泄漏可能会导致堆上的内存不够用,严重时,程序就崩了。
内存泄漏原因:
1.丢失内存地址,例如重复给一个指针变量分配内存
2.不使用的内存没有free
自己分配的堆上的内存,没有手动free释放,进程结束后,操作系统会帮我们释放。
全局变量和静态变量是在编译的时候就分配到bss段或数据区的,
初始化静态或者全局变量的时候不能使用函数,例如malloc;注意这里说的是初始化,不是初始化之后的赋值
static int *pi = (int *)malloc(sizeof(int));报错
静态变量在编译的时候就分配的内存,这个时候malloc还不能执行了,改为
static int *pi;
pi = (int *)malloc(sizeof(int))
就可以了。
悬空指针:
int *p = (int*)malloc(sizeof(int)*10);
free(p);
把p所指向的内存释放后,p就成为了一个悬空指针,C语言中指针内存被释放后,指针还是指向原来的地址,但是我们不应该再
使用这块内存了,不然就犯了“释放后使用”错误。
所以一般释放后给指针赋值一个NULL:p=NULL
野指针:
没有初始化的指针,例如int *p;
void*指针:
void *指针具有与char*指针相同的形式和内存对齐方式
任何指针都可以赋值给void*指针,它可以被转换回原来的指针类型。
用void*指针的时候要小心,如果把指针类型转换为void*类型,它可能被转换成不是原来的指针类型。
使用void*函数:
一个最明显的例子,malloc函数的返回类型就是void*,如果不用void*的话,又该用什么返回类型了? int*么,显然不合适。C语言中malloc返回的时候会自动把void*转换成定义的指针类型,但是C++中不会。
NULL:
NULL宏在C中定义为:#define NULL ((void *)0),定义在stddef.h头文件中,ubuntu18.04中stddef.h的路径为
/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h
NULL被赋值给指针意味着指针不指向任何东西。