堆栈系列——内存分配

时间:2021-08-24
本文章向大家介绍堆栈系列——内存分配,主要包括堆栈系列——内存分配使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

内存的静态分配和动态分配

内存的静态分配和动态分配的区别主要是两个:
  一是时间不同。静态分配发生在程序编译和连接的时候。动态分配则发生在程序调入和执行的时候。

  二是空间不同。堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由函数malloc进行分配。不过栈的动态分配和堆不同,他的动态分配是由编译器进行释放,无需我们手工实现。

对于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区、静态数据区和动态数据区。

其中,动态数据区一般就是“堆栈”。“栈(stack)”和“堆(heap)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的数据都是互不干扰。一个堆栈可以通过“基地址”和“栈顶”地址来描述。全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。

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

所以,我们可以用动态内存分配就可以解决上面的问题。所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不像数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。从以上动、静态内存分配比较可以知道动态内存分配相对于静态内存分配的特点:
   1、不需要预先分配存储空间;
   2、分配的空间可以根据程序的需要扩大或缩小。 

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

1 void *malloc (unsigned int size)

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

内存的释放

静态内存是在程序一开始运行就会分配内存,直到程序结束了,内存才被释放。 动态内存是在程序调用在程序中定义的函数时才被分配,函数调用结束了,动态内存就释放。
例如:

 1 #include"stdio.h" 
 2 jiechen(int i) 
 3 {static int a=1;   //定义一个静态变量
 4 for(;a<=i,a++) 
 5 return a*i; 
 6 } 
 7 
 8 main() 
 9 {int a,i;   //定义动态变量
10 printf("enter number:") 
11 scanf("%d",&a); 
12 for(i=1;i<=a;i++) 
13   printf("i!=%d\n",jiechen(i));
14 } 

运行
输入3
结果为1!=1
2!=2
3!=3

由malloc系统函数分配的内存就是从堆上分配内存。从堆上分配的内存一定要自己释放。用free释放,不然就是术语——“内存泄露”(或是“内存漏洞”)—— Memory Leak。于是,系统的可分配内存会随malloc越来越少,直到系统崩溃。

栈内存分配
—————

1 char* 
2 AllocStrFromStack() 
3 { 
4 char pstr[100]; 
5 return pstr; 
6 } 

堆内存分配
—————

1 char* 
2 AllocStrFromHeap(int len) 
3 { 
4 char *pstr; 
5 
6 if ( len <= 0 ) return NULL; 
7 return ( char* ) malloc( len ); 
8 }

对于第一个函数,那块pstr的内存在函数返回时就被系统释放了。于是所返回的char*什么也没有。而对于第二个函数,是从堆上分配内存,所以哪怕是程序退出时,也不释放,所以第二个函数的返回的内存没有问题,可以被使用。但一定要调用free释放,不然就是Memory Leak!

在堆上分配内存很容易造成内存泄漏,这是C/C++的最大的“克星”,如果你的程序要稳定,那么就不要出现Memory Leak。在使用malloc系统函数(包括calloc,realloc)时千万要小心。

对于malloc和free的操作有以下规则:

1) 配对使用,有一个malloc,就应该有一个free。(C++中对应为new和delete)
2) 尽量在同一层上使用,不要像上面那种,malloc在函数中,而free在函数外。最好在同一调用层上使用这两个函数。
3) malloc分配的内存一定要初始化。free后的指针一定要设置为NULL。


原文链接:https://blog.csdn.net/liuchao1986105/article/details/6724392

原文地址:https://www.cnblogs.com/zyf2021/p/15179132.html