#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> //动态内存开辟的常见错误 //1.对NULL的解引用操作 //int main() //{ // int* p = (int*) malloc(10000000000000000); // int i = 0;//没有对NULL==0的判断 // for (i = 0; i <= 10; i++) // { // *(p + i)=i; // } // return 0; //} 2.对动态开辟空间的越界访问 //int main() //{ // int i = 0; // int* p = (int*)malloc(10 * sizeof(int)); // if (p == NULL) // { // return 1; // } // for (i = 0; i <= 40; i++)//越界 // { // *(p + i) = i; // } // free(p); // p = NULL; // return 0; //} //3.使用free()释放非动态开辟的空间(只能是堆区) //int main() //{ // int arr[10]={0};//栈区 // int* p = arr; // free(p); // p = NULL; // return 0; //} //4.使用free()只释放非动态开辟的空间的一部分 //int main() //{ // int i = 0; // int* p = (int*)malloc(10 * sizeof(int)); // if (p = NULL); // return 1; // for (i = 0; i <= 5; i++) // { // *p++ = i; // } // free(p);//此时的p已经不是p指向的原来的位置,因为p此时已经无法通过p找到最初的空间, // //且如果此时通过p释放空间,此时的p=NULL,则变为释放*(p+4)的空间,错误 // p = NULL; // return 0; //} //5.对同一块内存开辟的空间多次释放 //int main() //{ // int* p =(int*) malloc(100); // // free(p); // // free(p);//多次释放--会出错,但是如果free(p);p=NULL;free(P);p=NULL,则无事发生 // p = NULL; // // return 0; //} //6.动态内存开辟忘记释放---在程序是24小时运行时,程序不会结束,内存一直泄露,浪费内存空间 //void test() //{ // int* p = (int*)malloc(10000); // if (p = NULL) // { // return 1; // } // //使用----使用之后已经无法返回,空间忘记释放 //} //int main() //{ // test(); // return 0; //} //动态开辟的空间两种回收方式: // 1.主动使用free() // 2.程序(不是函数)结束 //在堆上开辟和在栈上开辟的变量不一样,在堆上开辟不销毁,在栈上开辟销毁 //1.在堆上开辟时,地址有意义错误如下,改正如下 #include<string.h> //void GetMemory(char* p) //{ // p = (char*)malloc(100); // //} //void test(void) //{ // char* str = NULL; // GetMemory(str); // strcpy(str, "hello word"); // printf(str); //} // //int main() //{ // test(); // return 0; //} //错误理由: //str传给GetMemory函数的时候是值传递,所以Getmenory函数的形参p是str的一份临时拷贝,在Getmenory函数内部 //动态申请空间的地址,存放在p中,不会影响外边str,所以当Getmenory函数返回之后,str依然是NULL,所以strcpy //会失败 //当Getmenory函数返回后,形参p销毁,使得动态开辟的100个字节存在内存泄露,无法释放 //应改为(传址法) //char* GetMemory(char* p) //{ // p = (char*)malloc(100); //----malloc是在堆上开辟的 // return p; // //} //void test(void) //{ // char* str = NULL; // str=GetMemory(str);//传址 // strcpy(str, "hello word"); // printf(str);// // printf("hello word");//与str打印结果一样,因为传的是h的地址,h的地址所指的字符串 // free(str); // str = NULL; // //} //int main() //{ // test(); // return 0; //} //也可改为:(二级指针法) //void GetMemory(char** p) //{ // *p = (char*)malloc(100);//----malloc是在堆上开辟的 // //} //void test(void) //{ // char* str = NULL; // GetMemory(str); // strcpy(str, "hello word"); // printf(str); // free(str); // str = NULL; //} //int main() //{ // test(); // return 0; //} //2.在栈上开辟时,(如数组等局部变量)地址没意义 //char* GetMemory(void) //{ // char p[]="hello word"; //----malloc是在栈上开辟的,出了函数,p数组空间就还给操作系统, // //返回地址是没有实际意义的,如果通过地址访问内存,就是非法内存 // return p; // //} //void test(void) //{ // char* str = NULL; // str=GetMemory(); // printf(str); // //} //int main() //{ // test(); // return 0; //} int* f1(void) { int x = 10;//在栈区内创建的局部变量x出了函数就销毁,取地址无意义 return(&x); int* ptr;//局部变量不初始化就是随机值,是野指针 *ptr = 10; return ptr; } //全局变量,静态变量,static修饰局部变量,放数据段---静态区----代码段----常量字符串,可执行代码,指针代码 //局部变量,局部数组等放栈上 //malloc,calloc,realloc放在堆上