C语言---动态内存管理(2)https://developer.aliyun.com/article/1544470
5.动态内存经典笔试题分析
1.传值不如传址
//传过来的仅仅只是指针变量,并不是地址,所以这里的p起始是一份拷贝品 //改变p改变不了str void GetMemory(char* p)//这里的形参是实参的一份临时拷贝的 //相当与将str内的NULL传给p,那么p里面得到就是空指针 { p = (char*)malloc(100);//申请100个字节的空间,将这个空间的地址赋值给p //那么p就有能力找到这个空间了 //这个函数结束了 } void Test(void) { char* str = NULL; //指针变量str,里面放的是空指针 GetMemory(str); //将str传过去,这里的str是指针变量,里面存着NULL的地址 strcpy(str, "hello world");//这里的str依然为空指针,因为str并没有因为p的改变而改变 //如果这里的str是空指针,那么这里就对空指针就进行了非法访问了 //一但对NULL进行解引用操作,程序就会崩溃的 //上面函数内的malloc函数申请的空间并没有进行及时的释放内存,这样会造成内存泄漏的问题 printf(str);//printf接受了首元素地址就能进行打印了 } int main() { Test(); return 0; } //第一种解决方法: void GetMemory(char** p)//那么我们用二级指针变量进行接收 { *p = (char*)malloc(100); //对二级指针进行解引用得到的就是一级指针,这里就得到了str } void Test(void) { char* str = NULL; GetMemory(&str);//将地址传过去,因为str是一级指针变量 //经过这个函数,str里面放的就是100个字节的地址了 strcpy(str, "hello world");//将hello world拷贝过去 printf(str); free(str); str = NULL; } int main() { Test(); return 0; } //第二种方法 //char *GetMemory(char* p)//返回值p的类型是char*类型的 //{ // p = (char*)malloc(100); // return p;//直接将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; //} //我们甚至可以有第三种写法,在第二种写法的基础上 //我们这两个函数都可以不用传参 //开辟完空间直接将空间地址返回就行了 //完后让str进行一个接受就行了 char* GetMemory()//返回值p的类型是char*类型的 { char*p = (char*)malloc(100); return p;//直接将p返回 } void Test(void) { char* str = NULL; str = GetMemory();//用str来接收返回值 strcpy(str, "hello world"); printf(str); free(str); str = NULL; } int main() { Test(); return 0; }
2.函数内返回的变量地址就是野指针,因为变量在函数调用完之后就被销毁了
不如将变量返回,不能返回地址
典型的返回栈空间的问题
//char* GetMemory(void) //{ // char p[] = "hello world";//局部数组 // return p;//p是这个字符串的起始元素的地址 //} //void Test(void) //{ // char* str = NULL;//str里面放的是空指针 // str = GetMemory(); // printf(str); //} //int main() //{ // Test(); // return 0; //} /* 进入这个函数char* GetMemory(void) 我们向内存申请一块空间来放"hello world" 我们一但出了这个函数,这块空间就不属于我们了 这个函数返回之后,这块空间不属于我们了, 我们将返回地址放到str内,注定了str是个野指针 出了函数那块空间就没了 如果我们用malloc去开辟这块空间的话,如果我们不释放的话,那么p就一直指向了这块空间 这个问题的原因就是因为这个数组是临时的,进入使用,出去就被销毁了 这种局部变量就放在栈区上面的 典型的返回栈空间地址的问题,栈空间就是临时的空间 返回栈空间上地址的问题 我们可以将变量返回去 但是不能返回这个变量的地址 函数调用结束的话,原本的那块空间就销毁了 */ int test() { int a = 10; return a;//将a里面的10通过return 返回,那么n里面就接收到了10 }//a出了这个函数就销毁了 int main() { int n=test(); printf("%d ", n); return 0; } //如果返回的是地址的话,因为a已经出函数销毁了,那么我们就无法通过这个 //寻找到a,所以这个地址就成了野指针了
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(str); str = NULL; } int main() { Test(); return 0; } //这里的malloc没有进行内存释放 //造成内存泄漏问题 //忘记free
4.在free后,没有将str赋值为空指针,就会造成非法访问
//void Test(void) //{ // char* str = (char*)malloc(100); // strcpy(str, "hello"); // free(str);//将str指向的空间还给操作系统,无法继续使用了 // //但是str指向的地址还是那块空间的地址 // // //free完,str其实就是野指针了 // if (str != NULL)//真 // { // strcpy(str, "world"); // //我们要将这个字符串放到一个不属于我们的空间,这就形成非法访问了 // printf(str); // } //} // //int main() //{ // Test(); // return 0; //} //正确编写 void Test(void) { char* str = (char*)malloc(100); strcpy(str, "hello"); free(str); str = NULL;//及时将str赋值为空指针 ,是非法访问失效 if (str != NULL)//真 { strcpy(str, "world"); printf(str); } } int main() { Test(); return 0; }
C语言---动态内存管理(4)https://developer.aliyun.com/article/1544475