动态内存中关于GetMemory函数的几道问题
最佳答案 问答题库638位专家为你答疑解惑
学习完动态管理内存这部分内容之后,我们对它在实际问题中的应用可能还不是很了解,通过这几个例子我们来进一步巩固动态内存的相关知识。
目录
1.非法访问以及内存泄漏问题
1.1错误实例
1.2正确代码
2.返回栈空间地址,非法访问问题
2.1错误示例
2.2正确代码
3.野指针被使用的问题
3.1错误代码
3.2正确代码
1.非法访问以及内存泄漏问题
1.1错误实例
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h>void GetMemory(char* p) {p = (char*)malloc(sizeof(char) * 100);if (p == NULL){perror("malloc");return ;} } void Test(void) {char* str = NULL;GetMemory(str);strcpy(str, "hello world!");printf(str); } int main() {Test();return 0; }
我们会发现这个代码运行不出来
为什么会这样,我们来仔细分析一下:
这个代码存在两个问题
1.调用函数GetMemory时,我们传入str,这里传的是str本身,属于值传递,指针p得到的是str的值NULL,使用malloc函数后,假设开辟好的空间的首地址为0f12ff40,p指向这块空间的首地址,但是这与str无关,p是str的一份临时拷贝,有自己独立的空间,str的值依然为NULL,当GetMemory函数运行结束时,p被销毁,空间回收,malloc开辟好的空间我们无法得知在哪,我们没有机会释放malloc开辟的空间,存在内存泄漏
2.同时,我们在销毁了指针p后,依旧使用这块空间,对它进行strcpy,这是存在非法访问
1.2正确代码
我们有两种改正方法
1.第一种:我们以前学到过,修改一级指针要用二级指针,即用二级指针来接收一级指针的地址,同时,使用完这块空间后要进行释放
//正确代码 // //第一种改正 void GetMemory(char** p) {*p = (char*)malloc(sizeof(char) * 100);if (*p == NULL){perror("malloc");return ;} } void Test(void) {char* str = NULL;GetMemory(&str);//我们在这里传入一级指针的地址,用二级指针来接收strcpy(str, "hello world!");printf(str);//使用完之后我们要进行空间释放free(str);str = NULL; } int main() {Test();return 0; }
2.第二种:我们给GetMemory函数一个返回值,这样执行这个函数结束时,p指针不会被销毁,同时,使用完这块空间后要进行释放
//第二种改正 char* GetMemory(char* p) {p = (char*)malloc(sizeof(char) * 100);if (p == NULL){perror("malloc");return 1;}return p; } void Test(void) {char* str = NULL;str=GetMemory(str);//我们用指针str来接收函数返回值strcpy(str, "hello world!");printf(str);//使用完之后我们要进行空间释放free(str);str = NULL; } int main() {Test();return 0; }
如果认真看了我们写的代码,你可能会疑惑printf(str)这种输出函数的写法真的正确吗,我们下面来分析一下:
int main() {char* str = "abcdef";//这里str指向的是字符串的首地址也就是a的地址printf("%s\n", str);printf("abcdef\n");//这里打印时,传给printf函数的其实是字符串首地址a的地址printf(str);//所以我们这种写法是完全正确的,str中放的是a的地址,printf函数//接收的也是a的地址return 0; }
2.返回栈空间地址,非法访问问题
2.1错误示例
char* GetMemory(void) {char p[] = "hello world!";return p;//返回栈空间地址的问题 } void Test(void) {char* str = NULL;str = GetMemory();printf(str); } int main() {Test();return 0; }
我们分析一下这个代码:
p数组中存放“hello world!\0”,return p时,返回首字符的地址即h的地址,但同时返回这个首地址之后也释放了这块空间,归还了操作系统,我们没有权限使用这块空间,但是str接收了这块空间还打印了str,属于非法访问,越界访问
2.2正确代码
这种也有两种改法:
1.想要使用这块空间,我们需要把数组p变为指针p,这样就能找到这块空间,打印完整的字符串
//正确代码char* GetMemory(void) {char* p = "hello world!";return p; } void Test(void) {char* str = NULL;str = GetMemory();printf(str); } int main() {Test();return 0; }
2.把数组p变成静态区的变量,那么这块空间就不会被释放掉,里面存入的字符串也可以被打印
//第二种char* GetMemory(void) {static char p[] = "hello world!";//存入静态区return p; } void Test(void) {char* str = NULL;str = GetMemory();printf(str); } int main() {Test();return 0; }
3.野指针被使用的问题
3.1错误代码
//野指针被使用void Test(void) {char* str = (char*)malloc(sizeof(char) * 100);if (str == NULL){perror("malloc");return;}strcpy(str, "hello");printf(str);free(str);if (str != NULL){strcpy(str, "world!");printf(str);} } int main() {Test();return 0; }
我们查看代码,发现str被free后依旧被使用,此时,str是一个野指针,str指向的这块空间被释放,但是我们在释放后还想通过str这个指针来使用这块空间打印world!,这就形成了非法访问,我们以前就说过,虽然可以打印出来,但这是违法的,不安全
3.2正确代码
解决这个问题我们也有两种方法:
1.我们在free(str)后,应该把str主动置为NULL,确保不会形成野指针
//正确代码 void Test(void) {char* str = (char*)malloc(sizeof(char) * 100);if (str == NULL){perror("malloc");return;}strcpy(str, "hello");printf(str);free(str);str = NULL;//想要使用的话可以在重新开辟一块空间if (str != NULL){strcpy(str, "world!");printf(str);} } int main() {Test();return 0; }
2.在整体使用完之后再释放这块空间
void Test(void) {char* str = (char*)malloc(sizeof(char) * 100);if (str == NULL){perror("malloc");return;}strcpy(str, "hello");printf(str);strcpy(str, " world!");printf(str);//使用完之后在释放free(str);str = NULL; } int main() {Test();return 0; }
这就是我们应用动态开辟内存函数常遇到的问题,其实,只要大家书写时细心,这些问题是可以避免的,本期分享就到这里,大家下期再见!!!
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"动态内存中关于GetMemory函数的几道问题":http://eshow365.cn/6-30792-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!