全国咨询/投诉热线:400-618-4000

c/c++培训C语言核心知识总结(八)

更新时间:2016年10月21日16时39分 来源:传智播客C++培训学院 浏览次数:

八、堆区内存
 
#include <stdlib.h>
 
1. void* malloc(n * sizeof(int));
请求 n 个连续的、每个长度是一个int大小的堆空间,如果创建成功,将返回这个堆空间的首地址,如果创建失败,返回 NULL;
 
2. void* calloc(n, sizoef(int));
请求 n 个连续的、每个长度是一个int大小的堆空间,如果创建成功,将返回这个堆空间的首地址,如果创建失败,返回NULL ;
(和 malloc() 函数的区别在于,calloc()在创建成功后,会把空间自动初始化为 0 );
 
3. void *realloc(p, n * sizeof(int));
给一个已经分配了地址的指针 p 重新分配空间,p 是原来空间的首地址,n * sizeof(int) 基于这个首地址重新分配的大小;
1) 如果当前内存段后面有足够的内存空间,那么就直接扩展这段内存,realloc()返回原来的首地址;
2) 如果当前内存段后面没有足够的内存空间,那么系统会重新向内存树申请一段合适的空间,并将原来空间里的数据块释放掉,
而且 realloc() 会返回重新申请的堆空间的首地址;
3) 如果创建失败,返回 NULL, 此时原来的指针依然有效;
 
4.  void free();
1) free(p); 只是释放了申请的内存,系统将这块内存标记为可用。也就是可以被其他进程使用,但是并不改变 p 的指向;
2) p 所指向的内存空间被释放,所以其他程序就有机会使用这段空间了,相当于 p 指向了不属于自己的空间,里面的数据也是未知的。
(这个就叫野指针)
3) 为了避免野指针,最好在 free(p)之后,将 p = NULL; void *(0);
4) free()函数在执行的时候,其实是把这个块内存返回了内存红黑树上,让别人可以使用这块内存。
从逻辑上来说,释放p之后,你是不能再访问原先p指向的这块内存了,但是现在操作系统没有做到,
所以你还是可以访问到这块内存的,只是里面可能存有的数据不属于你。
free(p)之后,其实系统并没有做数据清空处理,所以你既可以访问这个空间,也可以用里面的值。
但是严格意义上来说,这样做是非法的!会造成野指针!
 
 
示例:
// 如何释放自定义函数内申请的堆空间
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
char *funcA();
char *funcB();
 
int a = 10; // 全局 初始化区域
char *p1; // 全局 为初始化区域
 
int main(void)
{
int b; // 栈区
char arr[] = "hello"; // 栈区
char *p2; // p2 在栈区
const char *p3 = "world!"; // p3 在栈区,"world!\0" 在常量区
 
static int c = 0; // 静态区 初始化区域
 
char *p;
 
p1 = (char *)malloc(20); // p1 指向堆区 20个字节
 
memset(p1, 0, sizeof(char) * 20); // 使用memset()函数将内存空间初始化为 0
strcpy(p1, "Are you Sleep?"); // "Are you Sleep?" 是在常量区
 
printf("%s\n", p1); // p1 指向的 拷贝到堆空间的 "Are you Sleep?" 的首地址,通过首地址打印这个字符串
 
p2 = funcB(); // p2 接收了funcB()回传堆空间首地址,可以通过这个地址找到funcA()申请的堆空间
 
free(p2); // 也可通过 p2 释放 自定义函数里申请的对空劲啊
free(p1);
 
p1 = NULL; // 安全起见,释放堆空间指针后, 重置将指针变量置为 NULL
p2 = NULL;
 
return 0; // 返回 0 给系统表示 main()正常执行结束,也就代表程序执行结束
}
 
char *funcA()
{
int a = 10;
const char *pa = "1234567";  // pa 在栈区, "1234567\0" 在常量区
char *pb = NULL;    // pb 在栈区,pb 占4字节(32bit system)
 
pb = (char *)malloc(20); // pb 指向了一个20个字节大小的堆空间
strcpy(pb, "Yes, I'm!"); // 拷贝 字符串给 pb,"Yes, I'm!\0" 在常量区
 
return pb; // 返回 指针变量 pb 保存的堆空间首地址给调用函数funcB()
}
 
char *funcB()
{
char *pa = NULL; // pa 是一个栈上的指针变量
pa = funcA(); // pa 接收了 funcA()函数返回的堆空间地址
return pa; // 返回指针变量 pa 保存的堆空间首地址给调用函数 main();
}
 
 
论空间分配速度:
栈区确实略快于堆区,
使用栈的时候,是直接从分配的地址里读取值,放到寄存器里,然后再放到目标地址。
使用堆的时候,是先将分配的地址放到寄存器里,然后再从这个地址里取值,再放到寄存器里,再放到目标地址。
 
论空间访问速度:
栈区和堆区是一样的,都是一个直接寻址的过程,没有区别。
 
 
CPU -> 寄存器 > L1 > L2 > L3 (属于缓存) > RAM(内存) > SRAM(主板的存储器) >  硬盘
CPU 只和 寄存器做数据存取,寄存器是用来存储临时数据的,对于需要重复操作的数据,会放到缓存里。
不管是寄存器还是缓存,数据都来自于内存, 内存呢又分为四个区....
本文版权归传智播客C++培训学院所有,欢迎转载,转载请注明作者出处。谢谢!
作者:传智播客C/C++培训学院
首发:http://www.itcast.cn/c/