呼伦贝尔网站建设厦门网站建设报价
news/
2025/9/23 16:10:59/
文章来源:
呼伦贝尔网站建设,厦门网站建设报价,网站建设及维护服务器,手机网站欣赏动态内存管理 1. 为什么存在动态内存管理2. 动态内存函数的介绍2.1 malloc函数和free函数2.2 calloc函数2.3 realloc函数 3. 常见的动态内存错误3.1 对NULL指针的解引用操作3.2 对动态开辟空间的越界访问3.3 对非动态开辟内存使用free函数3.4 使用free释放动态开辟内存的一部分… 动态内存管理 1. 为什么存在动态内存管理2. 动态内存函数的介绍2.1 malloc函数和free函数2.2 calloc函数2.3 realloc函数 3. 常见的动态内存错误3.1 对NULL指针的解引用操作3.2 对动态开辟空间的越界访问3.3 对非动态开辟内存使用free函数3.4 使用free释放动态开辟内存的一部分3.5 对同一块动态内存多次释放3.6 动态开辟内存忘记释放(内存泄漏) 4. 几道经典的笔试题4.1 题目一4.2 题目二4.3 题目三4.4 题目四 5. C/C程序的内存开辟6. 柔性数组6.1 为什么需要柔性数组6.2 柔性数组的定义6.3 柔性数组的使用6.4 柔性数组的特点6.5 柔性数组的优势 1. 为什么存在动态内存管理
我们已经掌握的内存开辟方式有 int val 20;//在栈空间上开辟四个字节 char arr[10] {0};//在栈空间上开辟10个字节的连续空间 但上述开辟内存的方式有两个特点
空间开辟大小是固定的数组在声明时必须指定数组的长度他所需要的内存在编译时分配
但是对于空间的需求不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道那数组的编译时开辟空间的方式就不能满足了。这时候就只能试试动态存开辟了。
2. 动态内存函数的介绍
2.1 malloc函数和free函数
C语言提供了一个动态内存开辟的函数 void* malloc (size_t size) 这个函数向内存申请一块连续可用的空间并返回指向这块空间的指针
如果开辟成功则返回一个指向开辟好空间的指针如果开辟失败则会返回NULL(空指针)因此malloc函数的返回值一定要做检查返回值的类型是void*所以malloc函数并不知道开辟空间的类型具体在使用时使用者自己决定如果size等于0这种行为C标准没有定义具体取决于编译器
C语言还提供了另一个函数free专门是用来做动态内存的释放和回收的 void free (void* ptr) 如果ptr指向的空间不是动态开辟的那么free的行为C语言并没有定义而是取决于编译器如果参数ptr是空指针(NULL)则该函数什么都不做
头文件: stdlib.h
#include stdio.hint main()
{//代码1int num 0;scanf(%d, num);int arr[num] {0};//代码2int* ptr NULL;ptr (int*)malloc(num*sizeof(int));if(NULL ! ptr)//判断ptr指针是否为空{int i 0;for(i0; inum; i){*(ptri) 0}}free(ptr);//释放ptr所指向的动态内存ptr NULL;//是否有必要return 0;
}注意:
malloc一定要和free搭配使用用完切记要释放内存ptrNULL是十分有必要的避免ptr成为野指针malloc函数只负责分配内存并不会将内存中的值初始化为0里面是一些随机值
2.2 calloc函数
C语言还提供了一个函数叫 calloc calloc 函数也用来动态内存分配。原型如下 void* calloc (size_t num, size_t size) 函数的功能是为num个大小为size的元素开辟一块空间并且把空间的每块区域初始化为0
#include stdio.h
#include stdlib.h
int main()
{int *p (int*)calloc(10, sizeof(int));if(NULL ! p){//使用空间}free(p);p NULL;return 0;
}2.3 realloc函数
realloc函数的出现让动态内存管理更加灵活有时会我们发现过去申请的空间太小了有时候我们又会觉得申请的空间过大了那为了合理的时候内存我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整
函数原型如下: void* realloc (void* ptr, size_t size) ptr是要调整的内存地址size 调整之后新大小返回值为调整之后的内存起始位置这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间realloc在调整内存空间的是存在两种情况 1.原来空间后面有足够大的空间 当是情况1 的时候要扩展内存就直接原有内存之后直接追加空间原来空间的数据不发生变化 2.原来的空间后面没有足够大的空间 当是情况2 的时候原有空间之后没有足够多的空间时扩展的方法是在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。 由于上述两种情况,在使用realloc函数时就要注意
#include stdio.h
int main()
{int *ptr (int*)malloc(100);if(ptr ! NULL){//业务处理}else{exit(EXIT_FAILURE); }//扩展容量//代码1ptr (int*)realloc(ptr, 1000);//这样可以吗(如果申请失败会如何)//代码2int*p NULL;p realloc(ptr, 1000);if(p ! NULL){ptr p;}//业务处理free(ptr);return 0;}注意: 不能用之前的指针直接指向realloc函数扩展的新空间因为如果扩展失败返回空指针那么意味着之前的空间找不到了就导致内存泄漏正确的做法是新创建一个指针去接收如果该指针不为空再将地址赋给原来的指针
3. 常见的动态内存错误
3.1 对NULL指针的解引用操作
void test()
{int *p (int *)malloc(INT_MAX/4);*p 20;//如果p的值是NULL就会有问题free(p);
}解决这个问题的方法是申请完的空间在使用前一定要判断不为空在使用
3.2 对动态开辟空间的越界访问
void test()
{int i 0;int *p (int *)malloc(10*sizeof(int));if(NULL p){exit(EXIT_FAILURE);}for(i0; i10; i){*(pi) i;//当i是10的时候越界访问}free(p);
}解决这个问题的方法是在访问时自己心里看清楚有没有越界在执行程序
3.3 对非动态开辟内存使用free函数
void test()
{int a 10;int *p a;free(p);//ok?
}这种做法也是错误的free只能释放动态开辟的内存解决方法是释放的时候看清楚
3.4 使用free释放动态开辟内存的一部分
void test()
{int *p (int *)malloc(100);p;free(p);//p不再指向动态内存的起始位置
}free函数只能释放一整个动态开辟的内存不能从中间某个位置开始释放 使用时要注意
3.5 对同一块动态内存多次释放
void test()
{int *p (int *)malloc(100);free(p);free(p);//重复释放
}free只能释放一次动态开辟的内存不能多次释放使用时要注意哦
3.6 动态开辟内存忘记释放(内存泄漏)
void test()
{int *p (int *)malloc(100);if(NULL ! p){*p 20;}
}
int main()
{test();while(1);}p指针是局部变量当调用完test函数时指针被销毁但申请的空间还在但没有之前的指针也就无法在访问这块地址这就导致内存一直被占用其他程序也无法使用这就是内存泄漏问题
切记: 申请的空间在使用完毕后一定要正确的释放
4. 几道经典的笔试题
4.1 题目一
void GetMemory(char *p)
{p (char *)malloc(100);
}void Test(void)
{char *str NULL;GetMemory(str);strcpy(str, hello world);printf(str);
}上面的程序test()函数执行会发生什么情况
GetMemory(str);将str的值传递给char*类型的指针p由于传的不是地址所以指针p和指针str指向的是不同的地址对于str来说地址里的值仍然是NULL对一个NULL去复制程序就会崩溃
4.2 题目二
char *GetMemory(void)
{char p[] hello world;return p;
}void Test(void)
{char *str NULL;str GetMemory();printf(str);
}请问执行Test()函数会发生什么
str GetMemory();这句话调用了GetMemory()函数并用char*指针接收该函数的返回值但char p[]数组是在该函数内部创建的虽然可以将数组p的地址返回给str但当str拿对应的地址去访问p之前的空间时这片空间已经被操作系统回收了所以就属于非法访问了打印出来是一些乱码
4.3 题目三
void GetMemory(char **p, int num)
{*p (char *)malloc(num);
}
void Test(void)
{char *str NULL;GetMemory(str, 100);strcpy(str, hello);printf(str);
}这道题看上去没什么大问题但是有一个细节在使用完动态开辟的内存后没有及时释放free()导致内存泄漏
4.4 题目四
void Test(void)
{char *str (char *) malloc(100);strcpy(str, hello);free(str);if(str ! NULL){strcpy(str, world);printf(str);}
}这道题问题在于在free完之后没有及时将指针str即使置NULL所以导致下面的if语句被执行但str开辟的空间已经被释放掉所以也属于非法访问了但是由于我们进行的是字符串的拷贝,所以world还是会被拷贝到当前地址并成功输出但我们要知道这实际上是错误的
5. C/C程序的内存开辟 C/C程序内存分配的几个区域
栈区stack在执行函数时函数内局部变量的存储单元都可以在栈上创建函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中效率很高但是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。堆区heap一般由程序员分配释放 若程序员不释放程序结束时可能由OS(操作系统)回收 。分配方式类似于链表。数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。代码段存放函数体(类成员函数和全局函数)的二进制代码。
6. 柔性数组
6.1 为什么需要柔性数组
我们平时在VS上只能指定长度固定的数组而不能灵活去改变数组的长度而且在定义一个数组时[ ]括号中必须是常量那么我们如果事先不知道要创建大小为多少的数组时应该怎么办?此时就需要C语言提供的另一种方式即柔性数组
6.2 柔性数组的定义
结构中的最后一个元素允许是未知大小的数组这就叫做『柔性数组』成员
typedef struct st_type
{int i;int a[0];//柔性数组成员
}type_a;//有些编译器不支持上述写法可以按照下面来定义typedef struct st_type
{int i;int a[];//柔性数组成员
}type_a;6.3 柔性数组的使用
#include stdlib.h
struct Stu {int num;int grade[];
};
int main()
{struct Stu* p (struct Stu*)malloc(sizeof(struct Stu) 20);if (p ! NULL){p-num 100;for (int i 0;i 5;i){p-grade[i] i1;printf(%d\n, p-grade[i]);}}free(p);p NULL;
}在内存中num和grade在一个开辟的动态内存中
6.4 柔性数组的特点
结构中的柔性数组成员前面必须至少一个其他成员。sizeof 返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结构用malloc ()函数进行内存的动态分配并且分配的内存应该大于结构的大小以适应柔性数组的预期大小。
6.5 柔性数组的优势
上述代码还可以设计为
#include stdlib.h
struct Stu {int num;int* ptr;
};int main()
{struct Stu* p (struct Stu*)malloc(sizeof(struct Stu));if (p ! NULL){p-ptr (int*)malloc(sizeof(int)*5);if (p-ptr ! NULL){for (int i 0;i 5;i){p-ptr[i] i 1;printf(%d\n, p-ptr[i]);}}}free(p-ptr);p-ptr NULL;free(p);p NULL;
}两者的区别在于在内存中的分布不同
情况一: 这种情况结构体变量是在栈中创建的柔性数组是在堆中创建的
情况二: 这种情况结构体和动态开辟的数组都是在堆上存储
第一种是通过柔性数组来实现第二种是通过普通的指针来实现我们来看看柔性数组的优势
第一个好处是方便内存释放
如果我们的代码是在一个给别人用的函数中你在里面做了二次内存分配并把整个结构体返回给用户。用户调用free可以释放结构体但是用户并不知道这个结构体内的成员也需要free所以你不能指望用户来发现这个事。所以如果我们把结构体的内存以及其成员要的内存一次性分配好了并返回给用户一个结构体指针用户做一次free就可以把所有的内存也给释放掉。
第二个好处是这样有利于访问速度.
连续的内存有益于提高访问速度也有益于减少内存碎片
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/913110.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!