wordpress网站设置关键词,网站专题页设计,服务器用来做网站空间,网站改版 请示目录 1.内存区域
2.void与void*
3.应用场景
4.malloc
5.calloc
6.realloc
7.free崩溃的原因
7.1引入
7.2具体原因
7.2.1越界
7.2.2指针移动
7.2.3重复释放同一段内存 1.内存区域
局部变量:定义在函数内部的变量,包括形参,在栈(stack)中,作用域在函数内部有效,生存周…目录 1.内存区域
2.void与void*
3.应用场景
4.malloc
5.calloc
6.realloc
7.free崩溃的原因
7.1引入
7.2具体原因
7.2.1越界
7.2.2指针移动
7.2.3重复释放同一段内存 1.内存区域
局部变量:定义在函数内部的变量,包括形参,在栈(stack)中,作用域在函数内部有效,生存周期:进入函数创建,退出函数销毁。
栈内存空间局部变量所在的内存区域系统自行管理内存的分配和回收容量小1M不同的系统存在差异堆内存空间动态内存所在的内存区域由程序员管理内存的分配和回收释放容量大1G不同的系统存在差异
2.void与void*
void:没有只能用于返回值或参数列表表示无返回值或无参数这个一般省略不写 void a;错误的 void*:通用指针或泛型指针,没有具体的数据类型的指针不能[],i等运算使用时需要强制类型转换
3.应用场景 1.需要根据变量作为长度定义数组。 2.函数结束后还需要继续使用的内存 ( 例如返回局部数组的地址 , 链表) 3.长度较大的数组 ( 大内存 , 超过栈 1M 的大小) 4.malloc
动态申请内存需要引用stdlib.h没有默认值具体参考帮助手册。
应用场景1.
//1.需要根据变量作为长度定义数组
int main()
{int n 10;//int arr[n];//error,变量不能作为数组的长度,C99合法int* p (int*)malloc(n * sizeof(int));//创建成功后,p类似数组名assert(p ! NULL);if (p NULL){perror(出错了);return 0;}for (int i 0; i n; i)p[i] i;for (int i 0; i n; i)printf(%d , p[i]);return 0;
}
应用场景2.
错误用法:
如下代码如果返回值为数组数组是局部变量函数结束后系统自行对变量进行回收这时return str,返回变量的地址地址仍存在并没有销毁,所以在主函数中打印函数的返回值时打印的是函数传的地址a返回函数传的地址取字符串此时字符串为随机值函数内的数据已经随函数的结束而销毁。
char* Getstr()
{char str[] hello world;//函数结束后系统自行对变量进行回收return str;//返回变量的地址地址仍存在并没有销毁
}int main()
{char* a Getstr();printf(%s, a);//乱码return 0;
}
辨析返回值为普通变量时为什么不用动态内存
如下代码在函数中返回的是整型a的具体值而不是它的地址。访问函数时直接将局部变量x赋值为a的值不会再跳转到a的地址再取a的值。
int Fun1() {int a 10;return a;//合法,返回的是a的值而不是地址
}int main() {int xFun1();printf(%d , x);return 0;
}正确写法如下,使用动态内存:
动态内存由程序员自行销毁可以用来函数传参使用完成后再释放。
char* GetStr()
{int len strlen(hello world);//char* str (char*)malloc(len * sizeof(char));//常见错误char* str (char*)malloc((len 1) * sizeof(char));assert(str ! NULL);strcpy(str, hello world);return str;
}int main()
{char* p GetStr();printf(%s\n, p);free(p);return 0;
} 应用场景 3( 需要大容量的内存 ) int main()
{//定义1000000长度的int数组//int arr[1000000];//不能定义这么大的数组//int* arr (int*)malloc(1000000 * sizeof(int));//ok//char* arr (char*)malloc(1024 * 1024 * 1024);//1G,okchar* arr (char*)malloc(1024 * 1024 * 1020 * 2);//20亿字节,2G失败if (arr NULL)perror(出错了);assert(arr ! NULL);printf(好了\n);getchar();free(arr);return 0;
} 5.calloc 申请内存函数 , 把每个元素初始化为 0, 具体参考帮助手册 int main()
{int n 10;int* arr (int*)calloc(n, sizeof(int));for (int i 0; i n; i)printf(%d , arr[i]);//输出n个 0free(arr);return 0;
} 6.realloc 扩大内存函数,具体参考帮助手册 (通常情况扩容后地址会改变而不是在原来的地址上进行扩容与操作系统的决策有关) int main()
{char *str;/* 最初的内存分配 */str (char *) malloc(15);strcpy(str, runoob);printf(String %s, Address %p\n, str, str);/* 重新分配内存 */str (char *) realloc(str, 25);strcat(str, .com);printf(String %s, Address %p\n, str, str);free(str);return(0);
} 7.free崩溃的原因 7.1引入 根据以往的编程经验在使用函数传递数组时形参包括数组的首地址arr和数组的长度len因为传递的是首地址是一个指针无法在函数内部根据sizeof(arr)/sizeof(数组类型)求得数组的长度所以形参必须包括数组的长度。 但是在使用free()释放内存空间时只传递了数组的首地址并没有传递数组的长度因为在申请动态内存时这段内存的头尾会分别生成标记标记也占一定的内存所以不需要传长度信息但是在操作时如果不小心破坏了这个标记在释放内存时就会发生错误。 int main() {int n 10;int* arr (int*)malloc(n * sizeof(int));arr (int*)realloc(arr, 2 * n * sizeof(int));//arr接收新的地址free(arr);//没有传长度申请的内存头尾会有标记占一定的内存不需要传长度信息return 0;
} 7.2具体原因 越界指针移动重复释放同一段内存释放不是动态创建的内存 7.2.1越界 越界会损坏所申请空间的结尾标志。 //1.越界
int main()
{int n 10;int* arr (int*)malloc(n);assert(arr ! NULL);for (int i 0; i n; i)arr[i] i;for (int i 0; i n; i)printf(%d , arr[i]);printf(\n);free(arr);return 0;
} int main() {int n 10;int* arr (int*)malloc(n * sizeof(int));assert(arr ! NULL);for (int i 0; i n; i)//越界申请空间的损坏结尾标志arr[i] 0;free(arr);//程序崩溃return 0;
}7.2.2指针移动 指针为数组首地址指针移动了,在释放时就找不到所申请空间的头部信息。 //指针移动
int main() {int n 10;int* arr (int*)malloc(10 * sizeof(int));for (int i 0; i n; i) {*arr 0;arr;//指针移动了,释放时找不到头部信息}free(arr);//崩溃return 0;
} 7.2.3重复释放同一段内存 //重复释放同一段内存
int main()
{int n 10;int* arr (int*)malloc(n * sizeof(int));assert(arr ! NULL);for (int i 0; i n; i){arr[i] i;}printf(%p\n, arr);free(arr);printf(%p\n, arr);//arr是野指针free(NULL);//可以//free(arr);//崩溃,重复释放return 0;
}