数组动态分配与静态分配的区别

简介: 数组动态分配与静态分配的区别

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


例如我们定义一个float型数组:float score[100]; 但是,在使用数组的时候,总有一个问题困扰着我们:数组应该有多大?


在很多的情况下,你并不能确定要使用多大的数组,比如上例,你可能并不知道我们要定义的这个数组到底有多大,那么你就要把数组定义得足够大。这样,你的程序在运行时就申请了固定大小的你认为足够大的内存空间。即使你知道你想利用的空间大小,但是如果因为某种特殊原因空间利用的大小有增加或者减少,你又必须重新去修改程序,扩大数组的存储范围。


这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的缺陷,特别是处理某些问题时:在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够大时,可能引起下标越界错误,甚至导致严重后果。


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


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

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


 内存的静态分配和动态分配的区别主要是两个:

 一是时间不同。静态分配发生在程序编译和连接的时候。动态分配则发生在程序调入和执行的时候。


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

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

 一般,用static修饰的变量,全局变量位于静态数据区。函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。


1、一维数组动态分配(1)


#include


//一维数组

void oneDimensionalArray()

{undefined

//定义一个长度为10的数组

int* array = new int[10];

//赋值

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

{undefined

array[i] = i*2;

}

//打印

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

{undefined

std::cout << i << " : " << array[i] << std::endl;

}

//释放内存

delete[] array;

}

注意:


int *p=new int[len];这一句,你不能这样做:int p[len];


C++编译器会报错说len的大小不能确定,因为用这种形式声明数组,数组的大小需要在编译时确定。而且这样也不行:


int p[]=new int[len];


编译器会说不能把int*型转化为int[]型,因为用new开辟了一段内存空间后会返回这段内存的首地址,所以要把这个地址赋给一个指针,所以要用int *p=new int[len];


注意要注销指针p,使程序释放用new开辟的内存空间。


一维数组动态分配(2)


假设动态构造一个Int型数组:

1 int *p = (int *)malloc(int len);

2 //还可以写作:

3 int *p = (int *)malloc(sizeof(int)*len);

4 int *p = (int *)malloc(sizeof(len));

5 数据类型 *p = (数据类型 *)malloc(sizeof(数据类型)*长度);

1.malloc只有一个int型的形参,表示要求系统分配的字节数

 2.malloc函数的功能是请求系统分配len个字节的内存空间,如果请求成功,则返回第一个字节的地址,如果请求失败,则返回NULL。


3.malloc函数能且只能返回第一个字节的地址,所以我们需要把这个无任何实际意义的第一个字节的地址(俗称干地址)转化成一个有实际意义的地址,nalloc函数前面必须加(数据类型 *),表示把这个无实际意义的第一个地址转化为相应类型的地址。如:


#include <stdio.h>

#include <stdlib.h>

int main()

{undefined

int n1,i;

int array;

printf(“请输入所要创建的一维动态数组的长度:”);

scanf("%d",&n1);

array=(int)calloc(n1,sizeof(int));

for(i=0;i<n1;i++)

{undefined

printf("%d\t",array[i]);

}

printf("\n");

for(i=0;i<n1;i++)

{undefined

array[i]=i+1;

printf("%d\t",array[i]);

}

free(array);//释放第一维指针

return 0;

}


2、二维数组动态创建


在创建动态数组的过程中我们要遵循一个原则,那就是在创建的时候从外层往里层,逐层创建;而释放的时候从里层往外层,逐层释放。


array=(int**)malloc(n1sizeof(int)); //第一维


以上是我们创建二维动态数组的最外层,创建好了最外层那么我们接下来就是要创建次外层了。这里使用了二级指针。


array[i]=(int*)malloc(n2* sizeof(int));//第二维


在创建次外层的过程中我们使用了一个for语句,千万别忘了使用for循环语句,这是绝大多数人的一个易错点。


创建好了接下来我们该讲到释放了,而释放的时候从里层往外层,逐层释放。刚刚与我们上面的创建相反,在以上代码中我们首先使用了下面一个for循环来释放里层。


for(i=0;i<n1;i++)

{undefined

free(array[i]);//释放第二维指针

}

在通过以下语句来释放外层。


free(array);//释放第一维指针


#include

#include <stdlib.h>

using namespace std;


int main(){undefined

int num1,num2;

cout<<“请输入动态二维数组的第一个维度:”;

cin>>num1;

cout<<“请输入动态二维数组的第二个维度:”;

cin>>num2;

int **array = (int *)calloc(num1,sizeof(int));

for(int i=0;i<num1;i++) {

array[i] = (int)calloc(num2,sizeof(int));

}

for(int i=0;i<num1;i++){undefined

for(int j=0;j<num2;j++){undefined

array[i][j] =i*num2+j+1;

printf("%d\t",array[i][j]);

}

cout<<endl;

}

for(int i=0;i<num1;i++) free(array[i]);

free(array);

return 0;

}

3、三维数组动态创建


#include <stdlib.h>

#include <stdio.h>

int main()

{undefined

int n1,n2,n3;

int array;

int i,j,k;

printf(“请输入所要创建的动态数组的第一维长度:”);

scanf("%d",&n1);

printf(“请输入所要创建的动态数组的第二维长度:”);

scanf("%d",&n2);

printf(“请输入所要创建的动态数组的第三维长度:”);

scanf("%d",&n3);

array=(int)malloc(n1sizeof(int**));//第一维

for(i=0; i<n1; i++)

{

array[i]=(int**)malloc(n2sizeof(int*)); //第二维

for(j=0;j<n2;j++)

{undefined

array[i][j]=(int*)malloc(n3*sizeof(int)); //第三维

}

}

for(i=0;i<n1;i++)

{undefined

for(j=0;j<n2;j++)

{undefined

for(k=0;k<n3;k++)

{undefined

array[i][j][k]=i+j+k+1;

printf("%d\t",array[i][j][k]);

}

printf("\n");

}

printf("\n");

}

for(i=0;i<n1;i++)

{undefined

for(j=0;j<n2;j++)

{undefined

free(array[i][j]);//释放第三维指针

}

}

for(i=0;i<n1;i++)

{undefined

free(array[i]);//释放第二维指针

}

free(array);//释放第一维指针

return 0;

}

4、动态数组创建后,不满足需求,继续扩大或缩小数组


4.1缩小动态数组


#include <stdio.h>

#include <stdlib.h>

int main()

{undefined

intn,p;

int i,n1,n2;

printf(“请输入所要创建的动态数组的长度:”);

scanf("%d",&n1);

n=(int)calloc(n1,sizeof(int));

for(i=0;i<n1;i++)

{

n[i]=i+1;

if(i%5==0)

printf("\n");

printf("%d\t",n[i]);

}

printf("\n请输入所要缩小的动态数组的长度:");

scanf("%d",&n2);

p=(int)realloc(n,(n2)*sizeof(int));

for(i=0;i<n2;i++)

{undefined

if(i%5==0)

printf("\n");

printf("%d\t",p[i]);

}

printf("\n");

free§;

return 0;

}

4.2扩大动态数组


#include <stdio.h>

#include <stdlib.h>

int main()

{undefined

intn,p;

int i,n1,n2;

printf(“请输入所要创建的动态数组的长度:”);

scanf("%d",&n1);

n=(int)calloc(n1,sizeof(int));

printf(“请输入所要扩展的动态数组的长度:”);

scanf("%d",&n2);

p=(int)realloc(n,(n2)*sizeof(int));//动态扩充数组

for(i=0;i<n2;i++)

{undefined

p[i]=i+1;

if(i%5==0)

printf("\n");

printf("%d\t",p[i]);

}

free§;

return 0;

}


相关文章
|
1月前
|
存储 C++
C/C++数据类型从0到内存具体分配详解
C/C++数据类型从0到内存具体分配详解
|
17天前
|
C语言
如何建立内存的动态分配
如何建立内存的动态分配
17 2
|
1月前
|
存储 C语言
怎样建立内存的动态分配
怎样建立内存的动态分配
10 0
玩转JVM中的对象及引用:从创建到引用到分配和优化策略
类加载检查 当Java虚拟机遇到一条new指令的时候,它会先去运行时常量池中寻找new的类的符号引用,并且检查这个符号引用所代表的类是否已经被加载、解析、初始化过。如果没有即需要进行相应的类加载过程。
|
存储 缓存 算法
【JVM深度解析】对象的分配策略栈上分配与TLAB
JVM是如何自动进行内存管理的呢?本文详细对象的分配策略,栈上分配与TLAB,相信相信大家看完已经掌握JVM是如何管理,本文适合点赞+收藏。
【JVM深度解析】对象的分配策略栈上分配与TLAB
|
监控 算法 Java
请问什么时候对象分配会不在 TLAB 内分配
请问什么时候对象分配会不在 TLAB 内分配
请问什么时候对象分配会不在 TLAB 内分配
|
存储 C++
c++实验2(1.重载的函数 2.const关键字 3.动态内存分配利用new运算分配内存空间,利用delete运算或程序运行结束释放内存。)
编写程序,定义2个重载函数add并在main函数中应用,功能。编写重载函数并验证,函数功能:对数组赋值。.编写程序,利用动态内存进行数据存储,实现功能:输入2个数据分别表示矩形的长和高,输出矩形的周长和面积。
143 0
静态&动态分配线性表
数据结构静态&动态分配线性表
静态&动态分配线性表
|
C语言
【C 语言】结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )
【C 语言】结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )
193 0
【C 语言】结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )
|
存储 算法 Java
(四)-对象内存的分配策略
Java所承诺的自动内存管理主要是:给对象分配内存,回收分配给对象的内存. 在Java虚拟机的五块内存空间中,程序计数器、Java虚拟机栈、本地方法栈内存的分配和回收都具有确定性,一般在编译阶段就能确定需要分配的内存大小,并且由于都是线程私有,因此它们的内存空间都随着线程的创建而创建,线程的结束而回收.也就是这三个区域的内存分配和回收都具有确定性,垃圾回收器不需要在这里花费太大的精力. 而Java虚拟机中的方法区因为是用来存储类信息、常量、静态变量,这些数据的变动性较小,因此不是Java内存管理重点需要关注的区域. 而对于堆,所有线程共享,所有的对象都需要在堆中创建和回收.虽然每个对象的
119 0

热门文章

最新文章