问题的提出
pro1.c
#include <stdio.h>
#include <stdlib.h>
main()
{
int *a=malloc(4);
*a=9999;
//*(a+1)=1000;
//*(a+1000)=10000;
printf("%p\n",a);
while(1);
}
gcc pro1.c -omain1 运行 main1 结果:0x8a01008
pro2.c
#include <stdio.h>
#include <stdlib.h>
main()
{
int *a=(int*)0x8a01008;//逻辑地址 没有与之相对应的物理地址 要建立关联才有意义 这个过程就是内存映射
printf("%d\n",*a);
while(1);
}
猜会不会打印9999
gcc pro2.c -omain2 运行 main2 结果:段错误
原因: 一个程序不能访问另外一个程序的地址指向的空间. 理解: 1.每个程序的开始地址0x80084000 2.程序中使用的地址不是物理地址,而是逻辑地址(虚拟内存). 逻辑地址仅仅是编号.编号使用int 4字节整数表示. 4294967296=4G 每个程序提供了4G的访问能力 问题: 逻辑地址与物理地址关联才有意义:过程称为内存映射.
结论: 虚拟地址与物理地址映射的时候有一个基本单位:至少会映射4K 4k 1000 内存页. 段错误:无效访问. 那段内存没有映射 非合法访问:比如malloc分配的空间之外的空间可以访问(没有段错误),但访问非法.因是越界访问 内存访问分两种:一个是可以访问,但不一定是合法的,比如malloc几个字节, 内存会给你映射4K空间,int* p=malloc(0); *(p+1000)=9999;理论说这是可以访问
四。虚拟内存的分配 栈:编译器自动生成代码维护,我们不用关心 堆:我们关心地址是否映射,映射的空间是否被管理。 1.brk/sbrk 内存映射函数 补充:帮助手册 man 节 关键字 1-8 1:Linux系统(shell)指令 man 1 ls; 2:系统函数 man 2 brk; 3:标准C函数 man fopen 一般在2和3节找 7:系统编程帮助 man 7 tcp(icmp;udp;socket) 分配释放内存: int brk(void *end);//分配空间,释放空间
void *sbrk(int size);//返回空间分配前的地址 然后内存内部当前指针移动size
应用: 1.使用sbrk分配空间 sbrk(非零整数) 2.使用sbrk得到没有映射的虚拟地址.第一次调用sbrk,sbrk(0)得到的是没有映射的虚拟首地址。 3.使用brk分配空间 4.使用brk释放空间
brk.c
#include <stdio.h>
#include <unistd.h>
main()
{
/*int *p=sbrk(0);没有映射空间的虚拟地址
*p=8888;*/ //会出现段错误
int *p1=sbrk(4);//分配4个字节 映射了一个页 内部当前指针移动4字节
*p1=8888;
//*(p+1024)=7777;//段错误
*(p1+1023)=7777;//没有段错误
printf("%d\n",*p1);
}
应用案例:
写一个程序查找1-10000之间所有的素数.见demo1.c
并且存放到缓冲,然后打印.
缓冲的实现使用sbrk/brk
流程:
循环
判定是否素数(isPrimer)
是,分配空间存放
不是,继续下步.
demo.c
#include <stdio.h>
#include <unistd.h>
int isPrimer(int a)
{
int i;
for(i=2;i<a;i++)
{
if(a%i==0)
{
return 1;
}
}
return 0;
}
main()
{
int i=2;
int b;
int *r;
int *p;
p=sbrk(0);
r=p;
for(;i<100;i++)
{
b=isPrimer(i);
if(b==0)
{
brk(r+1);
*r=i;
r=sbrk(0);
}
}
i=0;
r=p;
while(r!=sbrk(0))
{
printf("%d\n",*r);
r++;
}
brk(p);//free
}
总结: 智能指针 stl new malloc brk/sbrk比较适合大空间 异常处理 int brk(void*) void *sbrk(int); 如果成功.brk返回0 sbrk返回指针 失败 brk返回-1 sbrk返回(void*)-1
memerr.c
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
extern int errno;
int main()
{
void *p=sbrk(1000000000*3);
if(p==(void*)-1)
{
//perror("Hello:");
//printf("Memory:%m\n");
printf("::%s\n",strerror(errno));
}
}
Unix函数错误,修改内部变量:errno
字符串函数string.h cstring
内存管理函数malloc memset mamcmp memcpy ...
bzero
错误处理函数
标准IO函数
时间函数
类型转换函数
|