#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> //栈区:局部变量,局部数组,函数的形式参数 //堆区:动态内存分配 //静态区:全局变量,静态变量 全局数组 statint int a=10;
//如果不想浪费空间,了解创建变长数组
//动态内存分配 //1.malloc //2.free //3.calloc //4.realloc
//int main() //{ //int *p = (int *)malloc(10 * sizeof(int));//需要强制类型转换一下 ////malloc(这里不能为0) ////如果出现空间不够的情况下,会出现一个空指针。 //if (p == NULL) //{ // printf("%s\n", strerror(errno)); //} //else //{ // //正常使用空间 // int i = 0; // for (i = 0; i < 10; i++) // { // *(p + i) = i; // } // for (i = 0; i < 10; i++) // { // printf("%d", *(p + i)); // } //} ////当动态申请的空间不再使用的时候 //////就应该还给操作系统
////这里如果p指向的空间不是动态开辟的,那free函数的行为是未定义的
////如果p是空指针,则函数什么事都不做
//free(p);//p虽然被释放了,但还是有能力找到这块空间,所以附成空指针
////当再不需要这块空间之后,就放弃它
//p = NULL;
//malloc(10*sizeof(int))//修改总字节 效率高,但不初始化
//calloc效率低,但是初始化
//int*p = (int*)calloc(10, sizeof(int));//修改元素数,元素的大小
// //如果出现空间不够的情况下,会出现一个空指针。
//if (p == NULL)
//{
// printf("%s\n", strerror(errno));
//}
//else
//{
// //正常使用空间
// int i = 0;
// //for (i = 0; i < 10; i++)
// //{
// // *(p + i) = i;
// //}
// for (i = 0; i < 10; i++)
// {
// printf("%d", *(p + i));
// }
//}
////释放空间
////free函数是用来释放动态空间
//free(p);
//p = NULL;
//reallor//调整动态开辟内存的大小
//void* realloc(void* ptr,size_t size)
//ptr是要调整内存地址
//size 调整之后新大小
//返回值为调整之后的内存起始位置
//调整内存又来两种情况
//1.原有空间足够大
//2.后续空间不够扩展
//注意事项:
//1.如果p指向的空间之后有足够的内存空间可以追加,则直接追加,后返回p
//2.如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一个新的内存空间
//开辟一块满足需求的空间,并且把原来内存中的数据拷贝回来,释放旧的内存空间,最后返回新开辟的内存空间地址
//3.得用一个新的变量来接受realloc的返回值
//int* ptr = realloc(p, INT_MAX);
//if (ptr != NULL)//防止失败丢弃原来空间
//{
// p = ptr;
//}
//int* p2 = realloc(p, 40);
//int i = 0;
//for (i = 5; i < 10; i++)
//{
// *(p + i) = i;
//}
//for (i = 0; i < 10; i++)
//{
// printf("%d ", *(p2 + 1));
//}
//常见动态内存错误
//1.对空指针的解应用操作
//int *p = (int *)malloc(10 * sizeof(int));//需要强制类型转换一下
//没有分析malloc失败的情况 // int i = 0; // for (i = 0; i < 10; i++) // { // *(p + i) = i; // } // for (i = 0; i < 10; i++) // { // printf("%d", *(p + i)); // }
//2.对动态开辟空间的越界访问
//int *p = (int *)malloc(5 * sizeof(int));//需要强制类型转换一下
//if (p == NULL)
//{
// printf("%s\n", strerror(errno));
//}
//else
//{
// //正常使用空间
// int i = 0;
// for (i = 0; i < 10; i++)//上面只申请了20个字节
// {
// *(p + i) = i;
// }
// for (i = 0; i < 10; i++)
// {
// printf("%d", *(p + i));
// }
//3.对非动态开辟内存使用free释放
//int a = 10;//放在栈区
//int*p = &a;
//*p = 20;
//free(p);//在堆区上开辟
//p = NULL;
//4.使用free释放动态开辟内存的一部分
//int *p = (int*)malloc(40);
//if (p == NULL)
//{
// return 0;
//}
//int i = 0;
//for (i = 0; i < 10; i++)
//{
// *p++ = i;
//}
//free(p);
//p = NULL;
//5.对同一块内存多次释放
//int *p = (int*)malloc(40);
//if (p == NULL)
//{
// return 0;
//}
//使用
//释放
//free(p);
//p=NULL;
////.....
//free(p);
//6.动态开辟内存忘记释放(内存泄漏)
//while(1)
//{
//malloc(1)
//}
//void Getemory(char *p)//p是形参,是str的一份临时拷贝
// //空间开辟是开辟在P里面,不是开辟在str里面
// //存放的数字相同,存放的空间不同
//{
// p = (char *)malloc(100);
//}
//void Text(void)
//{
// char *str = NULL;
// GetMemory(str);
// strcpy(str, "hello world");//空指针就是0,追加到非法空间,导致非法访问,程序崩溃
// printf(str);
//}
//int main()
//{
// Test();
//}
//改正1
//void GetMemory(char **p)//2级指针
//{
// *p = (char*)malloc(100);
//}
//void Test(void)
//{
// char *str = NULL;//一级指针
// GetMemory(&str);//传地址,char**才能接收
// strcpy(str, "hello world");
// printf(str);
// free(str);
// str = NULL;
//}
//int main()
//{
// Test();
// return 0;
//}
//改正2
//char GetMemory(char *p)
//{
// p = (char*)malloc(100);
//return p; //}
//void Test(void)
//{
// char *str = NULL;
// str=GetMemory(str);
// strcpy(str, "hello world");
// printf(str);
//free(str); //str = NULL;
// free(str);
// str = NULL;
//}
//int main()
//{
// Test();
// return 0;
//}
//char *GetMemory(void)
//{
// char p[] = "hello world";//在栈空间上开辟空间
// return p;
//}
//void Test(void)
//{
// char *str = NULL;
// str = GetMemory();//p里面的是hello world 用完之后就释放了
// //再次访问不知道变成什么了,非法访问
// printf(str);
//}
//int main()
//{
// Test();
//}
//int * test()//错误
//{
// int a = 10;
// return &a;//在栈区上开辟空间
//}
//int main()
//{
// int *p = test();//也是非法访问
// *p = 20;
//}
//int * test()//正确
//{
// static int a = 10;//static修饰代码生命周期延长不销毁,开辟的空间放到静态区了
// return &a;//在栈区上开辟空间
//}
//int main()
//{
// int *p = test();//也是非法访问
// *p = 20;
//}
//int* test()
//{
// int *ptr = malloc(100);//堆空间申请的内存只有free才能回收
// return ptr;
//}
//int main()
//{
// int *p = test();
//}
//int *f2(void) //{ // int *ptr;//野指针 // *ptr = 10; // return ptr; //}
//void GetMemory(char **p, int num) //{ // *p = (char )malloc(num); //} //void Test(void) //{ // charstr = NULL; // GetMemory(&str, 100); // strcpy(str, "hello"); // printf(str); // //改 // free(str);//如果不写则造成内存泄漏 // str = NULL; //} // //int main() //{ // Test(); //} // return 0; //}
//void Test(void) //{ // char*str = (char *)malloc(100); // strcpy(str, "hello"); // free(str);//free释放之后,并不会把str置为NULL // str = NULL; // if (str != NULL) // { // strcpy(str, "world"); // printf(str); // } //}
//int main() //{ // Test(); //}
//柔性数组 //结构中最后一个元素是未知大小的数组,这就叫[柔性数组]的成员
//柔性数组的使用 //struct S //{ // int n; // int arr[0];//未知大小的-柔性数组成员-数组大小是可以变化的 //}; // //int main()//malloc和realloc共同配合使用 //{ //// struct S s; ////printf("%d\n",sizeof(s)); //struct S* ps = (struct S*)malloc(sizeof(struct S) + 5 * sizeof(int)); //ps->n = 100; //int i = 0; //for (i = 0; i < 5; i++) //{ // ps->arr[i] = i; //} //struct S*ptr = realloc(ps, 44);//对整个结构体变大小 //if (ptr != NULL) //{ // ps = ptr; //} //for (i = 5; i < 10; i++) //{ // ps->arr[i] = i; //} //for (i = 0; i < 10; i++) //{ // printf("%d ", ps->arr[i]); //} //free(ps); //ps=NULL; // //
// return 0; //}
struct S { int n; int *arr;//放一个地址 };
int main()//malloc和realloc共同配合使用 { struct S* ps = (struct S*)malloc(sizeof(struct S)); ps->arr = malloc(5 * sizeof(int));//申请的地址放到arr里面去 //两次malloc风险较大,释放注意先后顺序, //两次开辟的空间不连续,访问效率低一些 int i = 0; for (i = 0; i < 5; i++) { ps->arr[i] = i;//arr数组名代表首元素地址 }
for (i = 0; i < 5; i++)
{
printf("%d ", ps->arr[i]);
}
int *ptr = realloc(ps->arr, 10 * sizeof(int));//把arr弥补成10个整形的大小
if (ptr != NULL)//对arr这个指针指向的数组变大小
{
ps->arr = ptr;
}
for (i = 5; i < 10; i++)
{
ps->arr[i] = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", ps->arr[i]);
}
free(ps->arr);
ps->arr = NULL;
free(ps);
ps= NULL;
//柔性数组的好处:1方便释放内存,2有利于访问速度
return 0;
}