一、传统数组的缺点(*****)
1).数组长度必须事先制定,且只能是常整数,不能是变量
例子:
int a[5];//oK int len=5;int a[len];//error
2).传统形式定义的数组,该数组的内存程序员无法手动释放,在一个函数运行期间,系统为该函数中数组所分配的空间会一直存在,
直到该函数运行完毕时,数组的空间才会被系统释放
3).数组的长度一旦定义,其长度就不能在更改数组的长度不能在函数运行的过程中动态的扩充或缩小
4).A函数定义的数组,在A函数运行期间可以被其它函数使用,但A函数运行完毕之后,A函数中的数组将无法在被其他函数使用
传统方式定义的数组不能跨函数使用
二、为什么需要动态分配内存
动态内存很好的解决了传统数组的这4个缺陷
传统数组也叫静态数组
三、动态数组的构造
1、malloc函数的用法
/* malloc 的使用 malloc 是 memory(内存) allocate(分配)的缩写 */ # include <stdio.h> # include <malloc.h> //不能省 int main(void) { int i = 5; //分配了4个字节 静态分配 11 行 int * p = (int *)malloc(4); //12行 /* 1. 要使用malloc函数,必须添加malloc.h这个头文件 2. malloc函数只有一个形参,并且形参是整型 3. 4表示请求系统为本程序分配4个字节 4. malloc函数只能返回第一个字节的地址,所以需要强制类型转换告诉别人第一个字节的地址 指向的变量占几个字节 5. 12行分配了8个字节, p变量占4个字节, p所指向的内存也占4个字节 6. p本身所占的内存是静态分配的, p所指向的内存是动态分配的 */ *p = 5; //*p 代表的就是一个int变量, 只不过*p这个整型变量的内存分配方式和11行的i变量的分配方式不同 free(p); //freep(p)表示把p所指向的内存给释放掉 p本身的内存是静态的,不能由程序员手动释放, //p本身的内存只能在p变量所在的函数运行终止时由系统自动释放 printf("同志们好!\n"); return 0; }
2、通过被调函数修改主调函数变量的值
/*------------------------------------- 通过被调函数修改主调函数变量的值 ---------------------------------------*/ # include <stdio.h> # include <malloc.h> void f(int * q) { //*p = 200; //error //q = 200; //**q = 200; //error *q = 200; //free(q); //把q所指向的内存释放掉 本语句必须的注释掉,否则会导致第20行的代码出错,因为*p代表的是指向的地址, // 这里q会把*p的动态内存释放掉,访问权限就不属于这个程序了。 } int main(void) { int * p = (int *)malloc(sizeof(int)); //sizeof(int)返回值是int所占的字节数 *p = 10; printf("%d\n", *p); //10 f(p); //p是int *类型 printf("%d\n", *p); //200 第20行 return 0; }
3、动态内容分配举例--动态数组的构造
假设动态构造一个int型一维数组[至少保证要看懂]
int*p=(int*malloc(int len);
本语句分配了两块内存,一块内存是动态分配的,总共len个字节,另一块是静态分配的,并且这块静态内存是p变量本身所占的内存,总共4个字节
1)malloc只有一个int型的形参,表示要求系统分配的字节数
2)malloc函数的功能是请求系统1en个字节的内存空间,如果请求分配成功,则返回第一个字节的地址,如果分配不成功,则返回NULL
malloc函数能且只能返回第一个字节的地址,所以我们需要把这个无任何实际意义的第一个字节的地址(俗称干地址)转化为一个有实际意义的地址,
因此,malloc前面必须加(数据类型*),表示把这个无实际意义的第一个字节的地址转化为相应类型的地址。如:
int*p=(int*)malloc(50);
表示将系统分配好的50个字节的第一个字节的地址转化为int*型的地址,更准确的说是把第一个字节的地址转化为四个字节的地址,这样p就指向了第一个的四个字节,p+1就指向了第2个的四个字节,p+i就指向了第i+1个的4个字节。p[0]就是第一个元素,p[i]就是第i+1个元素。
double*p=(double*)malloc(80);
表示将系统分配好的80个字节的第一个字节的地址转化为double*型的地址,更准确的说是把第一个字节的地址转化为8个字节的地址,这样p就指向了第一个的8个字节,p+1就指向了第2个的8个字节,p+i就指向了第i+1个的8个字节。p[0]就是第一个元素,p[i]就是第i+1个元素。
4、freep(p);
表示把p所指向的内存给释放掉p本身的内存是静态的,不能由程序员手动释放,p本身的内存只能在p变量所在的函数运行终止时。
5、由系统自动释放静态内存和动态内存的比较【重点】
静态内存是由系统自动分配,由系统自动释放静态内存是在栈分配的。
动态内存是由程序员手动分配,手动释放动态内存是在堆分配的。
6、跨函数使用内存的问题【重点】
静态内存不可以跨函数使用
所谓静态内存不可以跨函数使用更准确的说法是:静态内存在函数执行期间可以被其它函数使用,静态内存在函数执行完毕之后就不能再被其他函数使用了。
动态内存可以跨函数使用,动态内存在函数执行完毕之后仍然可以被其他函数使用。
/*------------------------------------- 动态一维数组示例 ---------------------------------------*/ # include <stdio.h> # include <malloc.h> int main(void) { int a[5]; //如果int占4个字节的话,则本数组总共包含有20个字节,每四个字节被当做了一个int变量来使用 int len; int * pArr; int i; //动态的构造一维数组 printf("请输入你要存放的元素的个数: "); scanf("%d", &len); pArr = (int *)malloc(4 * len); //第12行 本行动态的构造了一个一维数组, 该一维数组的长度是len, 该数组的数组名是pArr, //该数组的每个元素是int类型 类似于 int pArr[len]; //对一维数组进行操作, 如:对动态一维数组进行赋值 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; } /*---------------------------------------------- 打印结果: 请输入你要存放的元素的个数: 6 1 2 3 4 5 6 一维数组的内容是: 1 2 3 4 5 6 Press any key to continue ------------------------------------------------*/
原文地址:https://www.cnblogs.com/zh-xiaoyuan/p/12639930.html