iOSDay08之C语言内存管理
2016-03-15 17:56
525 查看
本次主要学习和理解C语言中的内存管理
栈区的内存空间由系统自动分配和回收
栈顶,栈底:先定义的局部变量存储区域从栈底开始分配,后定义的局部变量向栈顶分配
特点:[b]先进后出,后进先出[/b]
当函数、循环、分支结束后,局部变量的生命周期结束,不能被使用,由系统自动回收内存空间
运行结果
![](http://images2015.cnblogs.com/blog/793084/201603/793084-20160315103045334-1862742846.png)
运行的结果a = 100是函数test1()中的值,只是当函数test1()运行结束后,栈区内存被自动回收,但是栈区不会将数据清空,当函数test2()再定义一个变量且不进行初始化时,输出就是上个变量的值。
[b] 栈区的内存安全问题:在函数中返回栈区的地址是不安全的![/b]
生命周期和整个程序一样长
运行结果
![](http://images2015.cnblogs.com/blog/793084/201603/793084-20160315112044928-1841266679.png)
为什么第二次的运行结果是12呢?
因为用static修饰的变量称为静态变量,它只能初始化一次,第二次函数调用时,static int s = 5; 并没有执行,故 s 的值为6,最后的结果是12
常量区的内容只能读取不能修改
代码区的内容只能读取不能修改
程序结束后,代码区的内存空间由系统回收
函数的作用:在堆区申请size个字节的存储空间,然后把存储空间的首地址返回
在堆区申请一块内存空间存放字符串
在堆区申请一块内存空间存放结构体变量
*p是结构体指针,结构体指针访问结构体成员变量的两种方法如下:
第一种:(*p).成员变量名
printf("第一种:(*p).成员变量名:name = %s, age = %d, gender = %c\n", (*p).name, (*p).age, (*p).gender);
第二种:使用指向运算符:-> ,格式:结构体指针变量(p) -> 成员变量
printf("第二种:使用指向运算符:->:name = %s, age = %d, gender = %c\n", p->name, p->age, p->gender);
完整的管理堆区内存代码
在C语言中访问空地址的存储空间会发生崩溃
运行结果
![](http://images2015.cnblogs.com/blog/793084/201603/793084-20160315172722506-2025005970.png)
野指针异常
野指针:指针指向了不属于自己管理的存储区域
练习:输入3个单词,动态分配内存保存单词,并在最后输出。
提示:定义一个指针数组 char * words[3] = {0}; 保存堆区空间的地址,堆区空间存储数据。
会将存储空间做清0操作,效率比malloc低
运行结果
![](http://images2015.cnblogs.com/blog/793084/201603/793084-20160315174109506-557333300.png)
[b]1、存储区划分[/b]
[b] [/b]按照地址从高到低的顺序:栈区,堆区,静态区,常量区,代码区1> 栈区:局部变量的存储区域
局部变量基本都在函数、循环、分支中定义栈区的内存空间由系统自动分配和回收
栈顶,栈底:先定义的局部变量存储区域从栈底开始分配,后定义的局部变量向栈顶分配
特点:[b]先进后出,后进先出[/b]
当函数、循环、分支结束后,局部变量的生命周期结束,不能被使用,由系统自动回收内存空间
void test1() { int a = 100; } void test2() { int a; // 栈区不会将数据清空,故输出为上个变量的值 printf("a = %d\n", a); } int main(int argc, const char * argv[]) { test1(); test2(); }
运行结果
![](http://images2015.cnblogs.com/blog/793084/201603/793084-20160315103045334-1862742846.png)
运行的结果a = 100是函数test1()中的值,只是当函数test1()运行结束后,栈区内存被自动回收,但是栈区不会将数据清空,当函数test2()再定义一个变量且不进行初始化时,输出就是上个变量的值。
[b] 栈区的内存安全问题:在函数中返回栈区的地址是不安全的![/b]
2> 静态区:静态变量和全局变量的存储区域
静态区的内存空间由系统自动分配和回收生命周期和整个程序一样长
int test3(int num) { static int s = 5; s++; return num += s; } int main(int argc, const char * argv[]) { printf("%d\n", test3(5)); printf("%d\n", test3(5)); }
运行结果
![](http://images2015.cnblogs.com/blog/793084/201603/793084-20160315112044928-1841266679.png)
为什么第二次的运行结果是12呢?
因为用static修饰的变量称为静态变量,它只能初始化一次,第二次函数调用时,static int s = 5; 并没有执行,故 s 的值为6,最后的结果是12
3> 常量区:常量的存储区域
常量区的内存空间由系统自动分配和回收常量区的内容只能读取不能修改
4> 代码区:所有的语句编译成二进制指令存放在代码区
代码区的内存空间由系统自动分配和回收代码区的内容只能读取不能修改
程序结束后,代码区的内存空间由系统回收
5> 堆区:由编程人员手动管理的区域(手动申请,手动释放)
2、内存分配函数
1> void *malloc(size)
void * 为任意类型的指针函数的作用:在堆区申请size个字节的存储空间,然后把存储空间的首地址返回
在堆区申请一块内存空间存放字符串
char str[] = "zifuchuan"; char *p = malloc(strlen(str) + 1); strcpy(p, str); printf("%s\n", str);
在堆区申请一块内存空间存放结构体变量
Student stu = {"xiaoming", 16, 'm'}; Student *p = malloc(sizeof(Student)); *p = stu;
*p是结构体指针,结构体指针访问结构体成员变量的两种方法如下:
第一种:(*p).成员变量名
printf("第一种:(*p).成员变量名:name = %s, age = %d, gender = %c\n", (*p).name, (*p).age, (*p).gender);
第二种:使用指向运算符:-> ,格式:结构体指针变量(p) -> 成员变量
printf("第二种:使用指向运算符:->:name = %s, age = %d, gender = %c\n", p->name, p->age, p->gender);
2> void free(void *)
释放开辟的存储空间完整的管理堆区内存代码
int *p = malloc(sizeof(int)); *p = 10; printf("%d\n", *p); free(p); p = NULL;
在C语言中访问空地址的存储空间会发生崩溃
int *p = malloc(sizeof(int)); 2 *p = 10; printf("%d\n", *p); free(p); p = NULL; printf("%d\n", *p);//访问空地址
运行结果
![](http://images2015.cnblogs.com/blog/793084/201603/793084-20160315172722506-2025005970.png)
野指针异常
野指针:指针指向了不属于自己管理的存储区域
int *p = malloc(sizeof(int)); *p = 10; printf("%d\n", *p); free(p); printf("%d\n", *p); // 野指针异常
练习:输入3个单词,动态分配内存保存单词,并在最后输出。
提示:定义一个指针数组 char * words[3] = {0}; 保存堆区空间的地址,堆区空间存储数据。
char *words[3] = {0}; char string[30] = {0}; for (int i = 0; i < 3; i++) { printf("请输入一个单词:\n"); scanf("%s", string); getchar(); // 根据单词的长度,在堆区开辟存储空间 words[i] = malloc(strlen(string) + 1); // 把输入的字符串拷贝到堆区内存中 strcpy(words[i], string); } printf("输出:\n"); for (int i = 0; i < 3; i++) { printf("%s\n", words[i]); free(words[i]); }
3、其他的内存操作函数
1> void *calloc(int n, unsigned size)
在堆区申请n * size 个字节的存储空间,并把存储空间的首地址返回会将存储空间做清0操作,效率比malloc低
int *p = malloc(sizeof(int) * 4); printf("%d %d %d %d\n", *p, *(p + 1), *(p + 2), *(p + 3)); int *q = calloc(4, sizeof(int)); printf("%d %d %d %d\n", *q, *(q + 1), *(q + 2), *(q + 3));
运行结果
![](http://images2015.cnblogs.com/blog/793084/201603/793084-20160315174109506-557333300.png)
2> void *realloc(void *, size)
在给定的地址空间的基础上,如果当前指针的地址足够大,那么将地址扩大,如果空间不足,那么重新找一块新的存储空间,然后释放原来指针指向的存储空间,把新的地址返回int *p_old = malloc(sizeof(int)); printf("%p\n", p_old); int *p_new = realloc(p_old, 12); printf("%p\n", p_new);
3> void *memset(void *, int, size)
在给定的地址空间开始,将 int 型的数值拷贝 size 次int *p = malloc(sizeof(int)); memset(p, 0, 4); // 将p指向的存储空间的数据置为0
4> void *memcpy(void *p, const void *q, unsigned long size)
从q指向的存储空间开始拷贝size个字节的数据到p指向的存储空间char name[] = "hello"; memcpy(name, "hi", 2); printf("%s\n", name);
5>int memcmp(const void *p, const void *q, size)
从p,q指向的地址开始比较size个字节的数据,相等为0,不等为-1int num1[] = {1, 2, 3}; int num2[] = {1, 3, 3}; int result = memcmp(num1, num2, sizeof(num1));// 相等为0,不等为-1 printf("result = %d\n", result);
相关文章推荐
- C++:为什么有容器与迭代器
- C语言找出数组中的特定元素的算法解析
- 《C++ Primer》第四版 第13章 复制控制
- C++纯虚函数
- C语言将数组中元素的数排序输出的相关问题解决
- C语言中的强符号与弱符号
- C++:冒号与双冒号用法
- C++
- c++ 走向高级之日积月累
- C++中this指针的用法及介绍
- C/C++问题汇总
- C++ pair
- C++之多态性与虚函数
- C语言输出旋转后数组中的最小数元素的算法原理与实例
- 关于C++的虚函数和多态性
- C++语言学习之对象和类
- 详解C语言求两个数的最大公约数及最小公倍数的方法
- C++虚函数表
- C语言是实现顺序表(非动态)
- Ubuntu Eclipse CDT C++11的支持