你是否清楚,每当你运行程序之际,操作系统都会针对你的数据开展内存分配操作。然而,存在着这样一类内存分配情形,一直到程序运行起来之后才能够知晓具体所需的空间大小,此即动态内存分配。它使得程序员能够以灵活的方式把控内存的使用状况,进而规避因静态分配所引发的空间浪费或者空间不足的问题。
int val = 20;//在栈空间上开辟四个字节
char arr[10] = {0};//在栈空间上开辟10个字节的连续空间
传统的数组以及变量,在编译这个时期的时候,就必然得确定下大小,这所代表的意思就是,你得提前去预估数据的量。当你着手处理用户输入这一情况,或者读取文件以及网络数据的时候,常常是没有办法预先知道确切大小的。要是预估的大小过小了,那么程序就有可能会崩溃;要是预估的过大了,那就会白白浪费宝贵的内存。
例如,你去编写一款图片处理软件,用户有可能打开大小为10MB的较小图片,也有可能打开容量为1GB的高清照片等。静态数组怎样都没办法去应对这种需求方面的变化情况。动态内存分配能够让程序在运行期间依据实际需求去申请空间,在使用完毕之后就进行释放操作,最终达成内存的高效利用目的。
void* malloc (size_t size);
void free (void* ptr);
用于释放动态内存的专门函数是free,忘记调用free会致使内存泄漏,程序占用的内存只会增加不会减少,最终有可能耗尽系统资源,正确的做法是在释放之后把指针设置为NULL,以此防止出现野指针,每回动态分配都一定要配对使用free,这属于C程序员的基本从业素养。
#include
#include
int main()
{
//申请5个整型的空间
int* p = (int*)malloc(5 * sizeof(int));
if (p == NULL)
{
perror("malloc");
return 1;
}
//使用
int i = 0;
for (i = 0; i < 5; ++i)
{
*(p + i) = i + 1;
}
for (i = 0; i < 5; i++)
{
printf("%d\n", *(p + i));
}
//释放
free(p);//释放ptr所指向的动态内存
p = NULL;//消除野指针
return 0;
}
calloc函数跟malloc相类似,然而,它具备两个参数,一个参数是元素个数,另一个参数是每个元素的大小。它会把所申请的内存初始化成0,从而省去手动进行清零的步骤。当你有需要数组并且期望所有元素初始值为零时,calloc是最佳的选择。
realloc被用来对已分配好的内存大小予以调整,它存在着两种结果,要是当前内存块的后面具备足够的空间,那么就在原地址处进行扩展,不然的话,就会在新的位置重新开展分配操作并且复制数据,在使用realloc的时候需要格外留意,绝对不可以依靠原指针直接去接收返回值,这是由于一旦分配遭遇失败,就会导致原内存地址遗失。
void* calloc (size_t num, size_t size);
被C99标准引入的柔性数组,使得结构体的最后一个元素能够成为未指定大小的数组,这样的设计致使结构体可携带可变 length 数据,同时维持内存连续性 ,柔性数组并不占用该结构体自身的大小,而是需要运用malloc额外去分配空间。
当运用柔性数组之际,整个结构体的内存呈现出连续的状态,举例而言,在对网络数据包结构予以定义之时,包头之后紧随着变长的数据,柔性数组能够将这种布局完美地予以达成,相较于将包头与数据区进行分开分配的情况,柔性数组使得内存碎片得以减少,进而提升了访问效率。
void* realloc (void* ptr, size_t size);
频频出现的内存泄漏,是极为常态的问题,特别是于结构繁杂的程序里,极易忘却予以释放。野指针也着实存有极大风险——其指针所指向的乃是已然被释放的内存,若持续加以使用可致使出现未定义的行为。而重复去释放同一块内存,同样会引发程序的崩溃。
还要说的一个陷阱是出现越界访问这种情况,动态分配的内存其边界并没有进行自动检查,要是写入超出所申请大小的数据就会致使堆结构遭到破坏,进而造成后续分配或者释放失败,而这些错误通常是隐蔽起来难以查找的,得借助像Valgrind这样的工具去进行检测。
程序内存一般被分成几个区域,栈区放置局部变量以及函数调用信息,是自动分配且自动释放的,堆区用来进行动态内存分配,需要程序员去手动管理,全局或者静态区存放全局变量和static变量,常量区存放字符串常量等只读数据,代码区存放程序指令。
不同片特定区域,存有不一样的生命周期,以及各异的访问权限。栈空间存在限制,不过速度较为快速,而堆空间较为宽广,但却需要进行手动管理。对于这些区域所具备的特性加以理解,能够对编写高效同时又安全的代码有所助益。动态内存分配所操作的便是堆区,这是 C / C++ 灵活性的核心具体展现。
你于编写程序实践期间碰到过哪些动态内存分配方面所存在的难题呢,欢迎于评论区域分享你的相关经验,点赞以便使更多的开发者能见到这些具备实用性的技巧呀!
#include
#include
int main()
{
//申请5个整型的空间
int* p = (int*)malloc(5 * sizeof(int));
if (p == NULL)
{
perror("malloc");
return 1;
}
//使用
int i = 0;
for (i = 0; i < 5; ++i)
{
*(p + i) = i + 1;
}
//空间不足,希望存储1~10
//调整空间
int* tmp = (int*)realloc(p, 10 * sizeof(int));
if (tmp == NULL)
{
perror("realloc");
return 1;
}
else
{
p = tmp;
tmp = NULL;
}
for (i = 5; i < 10; ++i)
{
*(p + i) = i + 1;
}
for (i = 0; i < 10; i++)
{
printf("%d\n", *(p + i));
}
//释放
free(p);
p = NULL;
return 0;
}
