数组内存分配概念

在这里解答一下:

int arr[4];

&arr[1] = arr[0] + sizeof(int) ;


静态分配, 即普通数组, 由于在栈中分配, 而栈的生成方向是自高地址向低地址生成。 所以有:

&arr[0] > &arr[1] ....

动态分配的数组。针对动态数组。 动态数组的内存分配在heap中。 而heap 的生成是由低地址向高地址生成。 所以有:

&arr[0] < &arr[1] <...

这是我以为的。  答案是我我错了。

测试一下:

  1. #include <iostream>  
  2.   
  3.   
  4. using namespace std;  
  5.   
  6.   
  7.   
  8.   
  9. int main() {  
  10.    int n = 4;  
  11.    int *ptr = new int[n];  
  12.   
  13.   
  14.    // dynamic array: on heap  
  15.        cout << "dynamic array: " << endl;  
  16.    for(int i = 0; i < 4; ++i) {  
  17.        cout << &ptr[i] << endl;  
  18.    }  
  19.   
  20.   
  21.    // ordinary array: on stack  
  22.    int arr[4];  
  23.    cout << "ordinary array: " << endl;  
  24.    for(int i = 0; i < 4; ++i) {  
  25.        cout << &arr[i] << endl;  
  26.    }  
  27.    return 0;  
  28. }  
#include <iostream>


using namespace std;




int main() {
   int n = 4;
   int *ptr = new int[n];


   // dynamic array: on heap
       cout << "dynamic array: " << endl;
   for(int i = 0; i < 4; ++i) {
       cout << &ptr[i] << endl;
   }


   // ordinary array: on stack
   int arr[4];
   cout << "ordinary array: " << endl;
   for(int i = 0; i < 4; ++i) {
       cout << &arr[i] << endl;
   }
   return 0;
}

结果如下:



为什么无论是静态数组还是动态数组, 数组元素的分配都是对元素从低地址到高地址。 

  无论动态还是静态 地址都是arr[0] < arr[1] 也就是数组内存是统一分配的
内部元素都是从低地址到高地址 。 
 
 
 
 
 
 

1、内存分配的三种方式:

1)、从静态存储区分配。数据的内存在程序编译时已经被分配,该内存在整个运行期间长期驻留,不会被释放;程序结束时,由操作系统自动释放。这类数据包括静态数据和全局数据。

2)、从栈空间分配。函数执行过程中,函数中的局部变量的内存,在栈上被分配;当函数调用完成后,随函数的返回空间也被释放。

3)、从堆空间分配。由开发者动态的申请内存,并手动的释放内存。

本文具体介绍动态内存分配,C语言中采用malloc、recalloc等函数分配内存;c++中使用new操作符申请内存。

malloc函数的返回值为void*,调用该函数时,需要显式的类型转化。返回值表示内存空间的首地址。如果该地址为NULL,表示系统没有满足的内存可供分配。因此在使用该地址之前,必须判断是否分配成功。例如:

int*p=(int*)malloc(sizeof(int)*10);

if(p != NULL)

{

......//使用该内存空间

}

在该内存使用完成后,需要开发者手动释放该内存:free(p):

这里需要注意:1)、调用free后,p和所指向的内存地址被断开,但是p的值仍然没有变化,此时如果调用p,将会出现错误,这时p就是一个野指针;因此当free(p);之后,应该将p的值赋为NULL,以免p再次调用出现错误。2)、虽然内存已经分配完成,但是并没有初始化,直接使用,取到的结果不正确。

4)、当malloc申请的内存不满足用户使用要求时,就需要重新分配内存,这时可以使用realloc函数。

 
 
void *realloc(
   void *memblock,
   size_t size 
);
memblock参数表示已经分配的内存地址的指针,即就是p;

size参数表示需要分配的字节数

该函数的返回值为,重新分配的内存空间的首地址。

realloc函数,在malloc函数已经分配的内存基础上再次扩充内存。realloc函数的返回值类型仍为void*。可以分三种情况来解释realloc。

情况一:需要分配的内存空间小于已经分配的空间。

那么这时只是从原来已经分配的内存空间中,将多余的空间释放,保留realloc函数需要的空间大小,将原来空间的的首地址赋值给realloc函数返回(这个地址和p的值是相同的);如果这样做的,可能会导致数据出错,因此一般不要缩小原内存空间;

情况二:需要分配的内存空间等于已经分配的空间。

将原来内存空间的首地址赋值给realloc函数返回;

情况三:需要分配的内存空间大于已经分配的空间。

1)如果原来的内存后,还有足够的空间,满足分配要求,那么直接在原来的内存的后面,分配适量的空间,并将原来空间的首地址赋值给realloc函数,返回;

2)如果原来内存后,没有足量的内存空间,满足分配要求,那么重新选择一块足量的空间分配,并将原来已经分配的空间的数据拷贝到新分配的内存中,将原指针p指向的空间释放。将新分配的空间首地址赋值给realloc函数返回,因此对于原来的空间,realloc函数在分配内存时,已经释放了原来的内存,不需要再次释放,否则会出错。

情况四:当分配的内存大小为0

系统是可以返回一个非NULL值,但是这个空间不能被使用。使用将会出错,效果等同于free(p);

情况五:当原来的指针为NULL

这种情况,的作用就相当于直接调用malloc函数一样;可以这样理解,NULL说明原空间没有分配成功,那么调用realloc函数,肯定需要分配一块新的内存空间,这不就相当于直接调用了malloc函数。

情况六:如果realloc函数调用失败

那么原来的空间地址不会被释放,保留原来的内存,该内存空间可以正常使用。


综上,在使用malloc函数时,需要注意几点:1)调用malloc函数后,需要判断内存是否分配成功;2)使用空间之前,需要给空间赋初始值;3)防止内存越界访问;4)释放内存空间之后free(p);,需要将原指针的值赋空(p=null;),以防再次使用产生错误,出现野指针;5)realloc函数对于原始的内存空间,在分配内存时已经做过处理,因此除realloc函数调用失败外,其余情况不能再次释放原空间内存,否则会出错。


2、既然malloc和free已经可以分配内存了,为什么还要引入new和delete?

首先需要明白,malloc和free是c语言中的c库函数,而new和delete是c++中的标识符;因此这两组拥有不同的性质;

接着,malloc和free不仅可以使用在C语言中,也可以使用在c++语言中,但是new和delete只是c++中特有的属性,在C语言中无法使用,因此new和delete有他的局限性;

再次,new和delete不仅需要分配内存空间,而且在面向对象的语言中,对于对象,还需要完成初始化,触发对象的构造和析构,这些操作是malloc和free无法完成的(笔者就在曾经实现链表的过程中,在结构体定义时,将一个数组元素定义为string类型的,在使用malloc申请内存后,调用过程中无法给该元素赋值。从这个例子中可以看出虽然malloc和new分配的内存大小相等,但是具体的内存内部工作还是有区别的)。

最后,malloc在分配内存时,需要开发者手动的指定元素的大小,并且返回值需要显式的类型转化;但是new就不需要指定和转化。


3、在c++中,既然new和delete可以完成所有分配的工作,为什么还要保留malloc和free?

这是因为c++编译器为了兼容c编译,是c中的所有函数可以在c++编译器上正常使用,因此保留了malloc和free

 
 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值