一:传统数组(静态数组)的缺点
1:数组的长度必须事先指定,并且是常整数,不能是变量 int a[5];
2:传统数组程序员无法由程序员释放,只能由系统释放。(并且只能在数组所在函数结束才能释放)
3:数组的长度在函数运行期间不能动态的扩充和缩小
4:A函数定义的传统数组,在A函数结束时,在B函数中是不能使用的,因为已经释放。也就是传统数组不能跨函数。
区分:静态存储与内存的静态开辟
二:为什么要动态分配内存
用来解决传统数组的四个缺陷
三:动态内存分配举例,以及动态数组的构造
方式:malloc函数,在堆开辟空间
int i =5; //静态分配
int *p = (int *) malloc(4); //动态分配 NULL (void *)0
1:malloc是由程序员在堆栈动态开辟空间
2:返回值开辟空间的首地址,但是类型是void ,需要强制类型转换
3:分配的内存空间应该能整除类型所占的字节数
4:包含头文件malloc.h
5:只能用free(p)来释放p所指向的动态开辟的内存空间。
6:对动态内存空间的操作,用p来操作。
7:可以用多个指针指向这个动态空间
8:当有多个指针只向这个动态空间时,只能用free一个指针,多次重复释放要被报错
9:可以将动态开辟的的内存指针作为函数参数
问题:p的分配类型是动态的还是静态的?当调用free(p)后,p的内存空间会被释放么?
例子:动态构建一个一维数组:
#include <stdio.h>
#include <malloc.h>
/*
动态构造数组
*/
int main(int argc, char *argv[]){
int len,i;
scanf("%d",&len);
int *p = (int *)malloc(4*len); //构造了一个一维数组,长度是4*len个字节
for(i=0;i < len;i++)
p[i] = i;
for(i=0;i < len;i++)
printf("%4d",p[i]);
free(p);
return 0;
}
动态扩充数组的长度,也就是在程序运行时动态扩充:realloc(首地址,总共字节数)
作用:将原来动态开辟的动态内存重新开辟一个字节数,如果这个数比以前的大,前面的数据保存。如果比原来的小,保留前面的数据。
#include <stdio.h>
#include <malloc.h>
/*
动态构造数组,并实现扩充与缩小
*/
int main(int argc, char *argv[]){
int len,i;
scanf("%d",&len);
int *p = (int *)malloc(20); //构造了一个一维数组,长度是4*len个字节
if(len > 5){
p = (int *)realloc(p,len*4);
}
for(i=0;i < len;i++)
p[i] = i;
for(i=0;i < len;i++)
printf("%4d",p[i]);
free(p);
return 0;
}
注意:扩充或者缩放的内存单元是新开辟的内存单元。这个过程中有值的拷贝过程。返回值是新开辟的地址空间首地址。
四:静态内存和动态内存的比较
静态开辟的内存:在栈中开辟,由编译器分配,由系统自动释放
动态开辟的内存:在堆中开辟,由程序员开辟,由程序员自动释放。
五:跨函数使用内存的问题
#include <stdio.h>
#include <malloc.h>
int main(int argc, char *argv[]){
void fun(int **);
int *p;
fun(&p); //要想在子函数修改p本省的值,只能发送p的地址
printf("%d ",*p);
return 0;
}
void fun(int **q){
*q = (int *)malloc(sizeof(int));
**q = 5;
}