动态内存分配【重点】
动态内存分配【重点难点】
传统数组的缺点:
1、数组长度必须事先制定,且只能是常数,不能是变量
例子:
int a[5]; //OK int len = 5; int a[len]; //error
2、传统形式定义的数组,该数组的内存程序员无法手动释放
在一个函数运行期间,系统为该函数中数组所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放
3、数组的长度一旦定义,其长度就不能再改变 数组的长度不能在函数运行的过程中动态的扩充或缩小
4、A函数定义的数组在A函数运行期间可以被其他函数使用,但A函数运行完毕之后,A函数中的数组将无法再被其他函数使用
传统方式定义的数组不能跨函数使用
为什么需要动态分配内存?
动态数组很好地解决了传统数组这四个缺点
传统数组也叫静态数组
动态内存分配举例——动态数组的构造【难点】
malloc 函数的使用(两个程序讲解)
/*
Date: 20/04/22 16:42
Description: 该程序没有实际含义
malloc 函数是 memory(内存) allocate(分配) 的缩写
*/
# include <stdio.h>
# include <malloc.h>
int main (void)
{
int i = 5; // 分配了 4 个字节 静态分配
int *p = (int *) malloc (4); //强制类型转换 指针变量本身占4个字节
/*
1、要使用 malloc 函数,必须添加 malloc.h 头文件
2、malloc 函数只有一个形参,并且形参是整型
3、malloc(4) 中的 4 表示请求系统为本程序分配四个字节
4、malloc函数只能返回第一个字节的地址,
5、12行分配了 8 个字节,p 变量占4个字节,p指向的内存也占四个字节
6、p本身所占的内存是静态分配的,p所指向的内存是动态分配的
*/
*p = 5; // *p 代表的就是一个 int 变量,只不过 *p这个整型变量的内存分配方式和 11行整型变量 i 的内存分配方式不同
free(p); //表示把 p 所指向的内存给释放掉 p 本身的内存是静态的,不能由程序员手动释放,只能在p变量所在的函数运行完毕后由系统释放
printf("hhh!\n");
return 0;
}
/*
Date: 20/04/22 17:17
Description: malloc 的用法
*/
# include <stdio.h>
# include <malloc.h>
void f(int *q) // q 是 p 的一份拷贝
{
// *p = 200; //error
// q = 200; //eooor
// **q = 200; //error 只有指针变量前面才能加 *,
*q = 200;
// free(q); // 把 q 指向的内存释放掉 ,该语句必须注释掉,否则会导致第23行的代码出错
}
void g(int ** p)
{
**p = 300;
}
int main (void)
{
int *p = (int *)malloc(sizeof(int)); // 23 行 sizeof(int)返回值是 int 所占的字节数
*p = 10;
printf("%d\n",*p); // 10
f(p); // p 是 int * 类型
printf("%d\n",*p); //200
g(&p); // p 是 int * 类型,&p 是 int ** 类型
printf("&p = %d\n",*p);
return 0;
}
/*
在DEVC++中输出的结果是
---------------------------------
10
200
&p = 300
--------------------------------
*/
构造动态一维数组(一个程序讲解)
/*
Date: 20/04/22 17:45
Description: 动态一维数组
*/
# include <stdio.h>
# include <malloc.h>
int main (void)
{
int a[5]; //如果int占 4个字节的话,则本数组总共包含有 20个字节,每4个字节被当作一个int变量来使用
int len;
int * pArr;
int i;
// 动态的构造一维数组
printf("请输入你要存放的元素的个数:");
scanf("%d",&len);
pArr = (int *)malloc(4 * len); // 相当于 int pArr[len] 本行动态地构造了一个一维数组,该数组的长度是 len,数组类型是 int,数组名是 pArr,
//对一维数组进行操作 如:对动态一维数组进行输出
for (i=0; i<len; ++i)
scanf("%d",&pArr[i]);
//对一维数组进行输出
printf("一维数组的内容是:\n");
for (i=0; i<len; ++i)
printf("%d\n",pArr[i]);
free(pArr); //释放掉动态分配的数组
return 0;
}
静态内存和动态内存的比较
静态内存由系统自动分配,由系统自动释放
静态内存是在栈中分配的
动态内存是由程序员手动分配,手动释放(不释放会造成内存泄漏)
动态内存是在堆分配的
【栈和堆的概念具体可参见数据结构】
跨函数使用内存的问题【难点】
预备知识:多级指针的使用【详见指针的用法】
静态变量不能跨函数使用详解【重点】 (一个程序讲解)
/*
Date: 20/04/23 13:03
Description: 静态变量不能跨函数使用 静态内存是在栈里分配的,出栈之后就不能使用了
该程序并没有实际含义
*/
# include <stdio.h>
void f(int **q) // q也是个指针变量,无论q是什么类型的指针变量,都只占4个字节
{
int i = 5;
// *q 等价于 p q 和 **q 都不等价于 p
// *q = i; // error 因为*q = i; 等价于 p = i; 这样写是错误的
*q = &i; // p = &i
}
int main (void)
{
int *p;
f(&p);
printf("%d\n",*p); //本程序语法没有问题,但是逻辑上有问题 (内存越界)
return 0;
}
动态变量可以跨函数使用详解【重点】 (一个程序讲解)
/*
Date: 20/04/23 18:47
Description: 动态内存是在堆里分配的,出栈不出栈没有影响
*/
# include <stdio.h>
# include <malloc.h>
void f( int **q )
{
*q = (int *)malloc(sizeof(int)); // sizeof(数据类型) 返回值是该数据类型所占的字节数
//等价于 p = (int *)malloc(sizeof(int));
// q = 5; // error
// *q = 5; // p = 5; p里面只能存地址
**q = 5; // *p = 5
}
int main (void)
{
int * p;
f(&p);
printf("%d\n",*p);
return 0;
}