一. 传统数组的缺点
1.数组的长度必须事先指定,且只能是常整数,不能是变量
例子:
int a[5] //OK
int len = 5; int a[len]; //error 现在C99版本可以使用了
2.传统形式定义的数组,该数组的内存程序员无法手动释放
在一函数运行期间,系统为该函数中数组所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放。
3.数组的长度一旦定义,其长度就不能再更改,数组的长度不能在函数运行的过程中动态的扩充或缩小
4.A函数定义的数组,在A函数运行期间可以被其他函数使用,但A函数运行完毕之后,A函数中的数组将无法在被其他函数使用
总结:传统方式定义的数组不能跨函数使用
二. 为什么需要动态分配内存
动态数组很好的解决了传统数组的这4个缺陷。
传统数组也叫静态数组
三. 动态内存分配举例_动态数组的构造
#include <stdlib.h>
malloc函数(memory allocation)动态内存分配
//从堆里面获得空间,分配长度为num_bytes字节的内存块函数,可向系统申请分配指定size个字节内存空间
int * p;
p = (int *)malloc(sizeof(int));
- malloc 函数原型:
void * malloc(unsigned int size);
void* 表示未确定类型的指针,void *可以指向任何类型的数据,更明确的说是指申请内存空间时还不知道用户是用这段空间来存储什么类型的数据(比如是char还是int或者…)
-
函数的作用:
系统自动在内存的动态存储区中,分配长度为size的一段连续空间。
若此函数执行成功,则函数返回值为指向被分配域的第一个字节的地址
(但是第一个字节地址没有实际含义,所以需要强制转换)
若该函数执行失败(如内存空间不足的情况),则函数返回值为空指针(NULL) -
malloc函数简单举例理解:
/* malloc 是memory(内存) allocate(分配) 的缩写 向malloc申请的空间的大小是以字节为单位的 */ #include <stdio.h> #include <malloc.h> int main(void) { int i = 5; //静态分配4个字节 int * p = (int *)malloc(4); /* 1. 要使用malloc函数,必须添加malloc.h这个头文件 2. malloc函数只有一个形参,并且形参是整型 3. 4表示请求系统为本程序分配4个字节 4. malloc函数只能返回第一个字节的地址 5. 11行分配了8个字节,p变量占4个字节,p所指向的内存也占4个字节 6. p本身所占的内存是静态分配的,p所指向的内存是动态分配的 */ *p = 5; //p已经指向了一块动态的空间,此时可以为这块空间赋值了 //*p代表的就是一个整型变量,只不过*p这个整型变量的内存分配和11行的i变量的分配方式不同 free(p); //free(p)表示把p所指向的内存给释放掉,p本身的内存是静态的, //不能由程序员手动释放,p本身的内存只能在p变量所在的函数运行终止时,由系统自动释放 return 0; }
-
malloc函数用法举例
#include <stdio.h> #include <malloc.h> //f函数里面修改以p的内容为地址的内存空间 void f(int * q) { *q = 200; // *p = 200; error // **q = 200; error // free(q); //把q所指向的内存释放掉,这一行必须注释掉,否则会导致第二个printf输出一个垃圾值 } int main(void) { int * p = (int *)malloc(sizeof(int));//sizeof(int)返回值是int所占的字节数 *p = 10; printf("%d\n", *p); //结果10 f(p); printf("%d\n", *p); //结果200 return 0; }
-
动态一维数组示例:
#include <stdio.h> #include <stdlib.h> int main(void) { int a[5];//如果int占4个字节的话,则本静态数组总共包含有20个字节,每四个字节被当做了一个int变量来使用 int len; int * pArr; //pArr是第一个字节地址,但它本身是int *类型所有它指向前4个字节地址 int i; //动态的构造一维数组 printf("请输入你要存放的元素的个数:"); scanf("%d", &len); pArr = (int *)malloc(sizeof(int)*len); //动态构造出了20个字节的一维数组,类似于int pArr[len]; //该数组的数组名是pArr,该数组的每个元素是int类型 //对动态一维数组进行赋值操作 for(i=0; i<len; i++) { scanf("%d", &pArr[i]); } //对一维数组进行输出 printf("一维数组的内容是:"); for(i=0; i<len; i++) { printf("%d ", pArr[i]); } free(pArr); //释放掉动态分配的数组 return 0; }
四. 静态内存和动态内存的比较
静态内存是由系统自动分配,有系统自动释放。
静态内存是在栈中分配的
只有在函数终止之后,静态变量的存储空间才会被系统释放
栈举例理解:
#include <stdio.h>
g(int i)
{
int a[5];
int k;
C;
}
f()
{
A;
g(5);
B;
}
int main(void)
{
f();
return 0;
}
动态内存由程序员手动分配,手动释放。
动态内存是在堆分配的(堆排序)
五. 跨函数使用内存的问题
- 静态变量不能跨函数使用
-
举例:
#include <stdio.h> void f(int ** q) //q是个指针变量,无论q是什么类型的指针变量,都只占4个(或8个)字节,由编译器所占位数决定 { int i = 5; *q = &i; //*q等价于p } int main(void) { int *p; f(&p); //当f函数运行完,为f所有分配的静态变量他们的空间都会被全部释放(p、i都是静态分配的) printf("%d\n", *p);//本语句语法没有问题,但逻辑上有问题 return 0; }
- 动态内存可以跨函数使用
-
举例:
#include <stdio.h> #include <malloc.h> void f(int ** q) { *q = (int *)malloc(sizeof(int)); //sizeof(数据类型):返回值是该数据类型所占字节数 //等价于 p = (int *)malloc(sizeof(int)) **q = 5; } int main(void) { int * p; f(&p); //动态分配的内存当f函数终止之后,sizeof(int)这个字节仍然属于p printf("%d\n", *p); return 0; }