在我们平时定义一个变量或一个数组时其大小为固定值。无法做到灵活多变,我们使用动态内存分配可以很好的解决问题。
void* malloc (size_t size);
其中size为需要申请的字节大小数,类型为size_t;
返回值为void* 成功时,指向函数分配的内存块的指针。此指针的类型始终为void*,可以将其转换为所需的数据指针类型,如果函数未能分配请求的内存块,则返回空指针。
在我们使用动态内存分配函数后,申请得到的内存要释放这里我们使用 :
void free (void* ptr);
来释放获得的内存。
举一个使用的例子。
#include<stdlib.h> #include<stdio.h> int main() { int *p = (int *)malloc(10 * sizeof(int)); int i = 0; for (i = 0; i < 10; i++) { p[i] = i; } for (i = 0; i < 10; i++) { printf("%d ", p[i]); } printf("\n"); free(p); return 0; }
void* calloc(size_t num,size_t size);
为num元素数组分配一个内存块,每个元素的大小为字节长,并将其所有位初始化为零。有效的结果是分配(num*size)字节的零初始化内存块。如果大小为零,则返回值取决于特定的库实现(它可能是空指针,也可能不是空指针),但不应取消对返回指针的引用。
#include<stdlib.h> #include<stdio.h> int main() { int *p = (int *)calloc(10, sizeof(int)); if (p == NULL) { return 1; } return 0; }
我们通过查看内存可以看到申请得到的空间确实被初始化为0。
在我们通过动态内存申请获得内存不够用时,可以使用realloc为其增加空间,其原型为
void* realloc (void* ptr, size_t size);
ptr为指向以前使用malloc、calloc或realloc分配的内存块的指针。或者,这可以是一个空指针,在这种情况下,将分配一个新块(就像调用了malloc一样)。
size为内存块的新大小,以字节为单位。size_t是无符号整数类型。
#include<stdlib.h> #include<stdio.h> int main() { int *p = (int *)malloc(10 * sizeof(int)); int i = 0; for (i = 0; i < 10; i++) { p[i] = i; } int *c = (int *)realloc(p, 20 * sizeof(int));//扩大容量 /*if (c != NULL) { p = c; } */ for (i = 10; i < 20; i++) { c[i] = i; } for (i = 0; i < 20; i++) { printf("%d ", c[i]); } printf("\n"); free(c); return 0; }
这里需要说明当内存中有足够的连续空间时则,分配向后的连续空间返回原指针。当连续空间不足时则会重新找一块新内存,将原来的数据复制下来,新的空间也可以使用。
若动态内存申请1失败则会返回空指针,此时对其解引用就会发生错误。
int main() { int *p=(int*)malloc(10* sizeof( int)); int i = 0; for (i = 0; i < 13; i++)//对动态内存分配的空间越界访问。 { p[i] = i; } free(p); return 0; }
int main() { int p = 0; free(p);//对非动态开辟内存使用free释放 return 0; }
void text() { int *p = (int *)malloc(10 * sizeof(int));//对一部分动态内存申请的释放。 p++; free(p); }
void text() { int *p = (int *)malloc(10 * sizeof(int));//对动态内存的多次释放。 free(p); free(p); }
虽然程序结束会自动释放,但在大项目中可能会造成严重的内存浪费。
下边是一个柔性数组。
struct student { int i; int a[];//也可写为a[0] };
结构中的柔性数组成员前面必须至少一个其他成员。
sizeof 返回的这种结构大小不包括柔性数组的内存。
包含柔性数组成员的结构用malloc函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
struct student { int j; int a[];//柔性数组 }a; int main() { int i = 0; struct student *p = (struct student*)malloc(sizeof(a)+100 * sizeof(int));//这样相当于a[100] p->j = 100; for (i = 0; i<100; i++) { p->a[i] = i; } free(p); return 0; }
柔性数组对于动态内存申请来说有以下两个优势
1.方便内存释放
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
2.这样有利于访问速度.
连续的内存有益于提高访问速度,也有益于减少内存碎片。