动态分配内存

时间:2023-01-29 22:06:24

动态分配内存

所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。

C/C++定义了4个内存区间:代码区,全局变量与静态变量区,局部变量区即栈区,动态存储区,即堆区或*存储区。

堆的概念:通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间。这种内存分配称为静态存储分配;有些操作对象只在程序运行时才能确定,这样编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配。所有动态存储分配都在堆区中进行。当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。

在使用数组的时候,总有一个问题困扰着我们:数组应该有多大?在很多的情况下,你并不能确定要使用多大的数组,比如上例,你可能并不知道我们要定义的这个数组到底有多大,那么你就要把数组定义得足够大。这样,你的程序在运行时就申请了固定大小的你认为足够大的内存空间。即使你知道你想利用的空间大小,但是如果因为某种特殊原因空间利用的大小有增加或者减少,你又必须重新去修改程序,扩大数组的存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的缺陷,特别是处理某些问题时:在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够大时,可能引起下标越界错误,甚至导致严重后果。

我们用动态内存分配就可以解决上面的问题. 所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。

从以上动、静态内存分配比较可以知道动态内存分配相对于静态内存分配的特点:

1、不需要预先分配存储空间;

2、分配的空间可以根据程序的需要扩大或缩小。

要实现根据程序的需要动态分配存储空间,就必须用到malloc函数.

malloc函数的原型为:void *malloc (unsigned int size) 其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。还有一点必须注意的是,当函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针。所以在调用该函数时应该检测返回值是否为NULL并执行相应的操作。

分配方法:
1.生成变量
(1)new可用来生成动态无名变量

如 int *p=new int;

int *p=new int [10]; //动态数组的大小可以是变量或常量;而一般直接声明数组时,数组大小必须是常量

又如:

int *p1;

double *p2;

p1=new int⑿;

p2=new double [100];

l 分别表示动态分配了用于存放整型数据的内存空间,将初值12写入该内存空间,并将首地址值返回指针p1;

l 动态分配了具有100个双精度实型数组元素的数组,同时将各存储区的首地址指针返回给指针变量p2;

对于生成二维及更高维的数组,应使用多维指针

以二维指针为例

int **p=new int* [row]; //row是二维数组的行,p是指向一个指针数组的指针

for(int i=0; i<row; i++)

p=new int [col];     //col是二维数组的列,p是指向一个int数组的指针

删除这个二维数组

for(int i = 0; i < row;i++)

delete []p; //先删除二维数组的列

delete []p;

使用完动态无名变量后应该及时释放,要用到 delete 运算符

delete p; //释放单个变量(或者free(p);   释放内存)

delete [ ] p; //释放数组变量(不论数组是几维)

相比于一般的变量声明,使用new和delete 运算符可方便的使用变量。

2.malloc函数

原型:extern void *malloc(unsigned int num_bytes);

头文件:在TC2.0中可以用malloc.h或 alloc.h (注意:alloc.h 与 malloc.h 的内容是完全一致的),而在Visual C++6.0中可以用malloc.h或者stdlib.h

功能:分配长度为num_bytes字节的内存块

返回值:如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。函数返回的指针一定要适当对齐,使其可以用于任何数据对象。

说明:关于该函数的原型,在旧的版本中malloc返回的是char型指针,新的ANSIC标准规定,该函数返回为void型指针,因此必要时要进行类型转换。

名称解释:malloc的全称是memory allocation,中文叫动态内存分配,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存。

常见错误:

使用动态内存分配的程序中,常常会出现很多错误。

1. 对NULL指针进行解引用操作

2. 对分配的内存进行操作时越过边界

3. 释放并非动态分配的内存

4. 试图释放一块动态分配的内存的一部分以及一块内存被释放之后被继续使用。

说明:

1. 动态分配最常见的错误就是忘记检查所请求的内存是否成功分配。

2. 动态内存分配的第二大错误来源是操作内存时超出了分配内存的边界。

3. 当你使用free时,可能出现各种不同的错误。

1>传递给free的指针必须是一个从malloc、calloc或realloc函数返回的指针。

2>传递给free函数一个指针,让它释放一块并非动态分配的内存可能导致程序立即终止或在晚些时候终止。

3>试图释放一块动态分配内存的一部分也有可能引起类似问题。

4>不要访问已经被free函数释放了的内存。假定对一个指向动态分配的内存的指针进行了复制,而且这个指针的几份拷贝分散于程序各处。你无法保证当你使用其中一个指针时它所指向的内存是不是已被另一个指针释放。还要确保程序中所有使用这块内存的地方在这块内存释放之前停止对它的使用。

5>当动态分配的内存不再需要使用时,应该被释放,这样可以被重新分配使用。分配内存但在使用完毕后不释放将引起内存泄漏(memory leak)。

总结:

1.当数组被声明时,必须在编译时知道它的长度。动态内存分配允许程序为一个长度在运行时才知道的数组分配内存空间。

2.malloc和calloc函数都用于动态分配一块内存,并返回一个指定该块内存的指针。

1>malloc的参数就是需要分配的内存的字节数。

2>calloc的参数是需要分配的元素个数和每个元素的长度。calloc函数在返回前把内存初始化为零。malloc函数返回时内存并未以任何方式进行初始化。

3>调用realloc函数可以改变一块已经动态分配的内存的大小。增加内存块大小有时有可能采取的方法是把原来内存块上的所有数据复制到一个新的、更大的内存块上。当一个动态分配的内存块不再使用时,应该调用free函数把它归还给可用内存池,内存释放后便不能再被访问。

3.如果请求的内存分配失败,malloc、malloc和readlloc函数返回的将是一个NULL指针。

4.错误的访问分配内存之外的区域所引起的后果类似越界访问一个数组,但这个错误还能破坏可用内存池,导致程序失败。

5.如果一个指针不是从早先的malloc、calloc或realloc函数返回的,它是不能作为参数传递给free函数的。