Day25、malloc 内存分配、mmap内存映射、文件的操作(文件描述符、open\close\read)

回顾昨天内容

1、 错误的处理

error 全局变量,在函数调用失败的时候,会给errno赋值一个整数,这个整数是错误号。我们可以根据错误号找到错误原因(错误的描述信息)

两个错误处理函数:perror(3)、strerror(3 )

2、 进程的环境变量

每个进程都有一个环境变量列表

environ 全局变量,它指向了一个字符串列表(环境变量列表)

int main(int argc, char *argv[ ] , char*env[ ] );

操作环境变量的几个函数:

getenv(3) setenv(3)  putenv(3)  unsetenv(3) clearenv( 3 )

3、 进程映射

32位机、单核:每个进程可以访问4G的地址空间,进程的内存空间分为用户空间和内核空间。用户空间占3G,内存空间占1G

进程内存布局:

代码段、数据段、BSS段、堆、栈 (在昨天笔记里,堆和栈是有区别的

全局变量、静态变量  在数据段

auto和局部变量     栈

malloc 分配的内存   heap 堆

“tarena”          在代码段

生命周期: 每个函数都有一个栈帧,函数运行时该栈帧有效,当这个函数执行完毕时,其栈帧也随其结束,函数使用的内存空间也就释放,所以栈帧中的局部变量也就失效。

堆、数据段、代码段 它们的生命周期是整个进程的生命周期,随着进程的结束而结束。

 

一、            malloc 内存分配

malloc (3)

#include <stdlib.h>

void *malloc(size_t size);

void free(void *ptr);

功能:

参数:要分配的地址空间大小

返回值:分配的空间的地址

举例说明:

char *p=(char *)malloc(32);

strcpy(p,”tarena”);

free(p);

printf(“%s\n”,p);   \\ 地址内容已经被释放了,可能有新的内容填进去

p=null; \\ 指针不使用的时候需要置空

printf(“%s\n”,p);

内存分配举例:malloc.c

  1#include<stdio.h>

  2#include<stdlib.h>

  3int main(int argc,char *argv[]){

 4     int *p=(int*)malloc(sizeof(int));

 5     char *p1=(int*)malloc(4096);

 6     char *p2=(int*)malloc(4096*32);

 7     char *p3=(int*)malloc(4096);

 8     getchar();  //留作观察

 9     free(p);

 10    p=NULL;

 11    return 0;

 12}  

tarena@tarena-virtual-machine:~$ ps -aux

0990a000-0992b000 rw-p 00000000 00:000          [heap]

当调用malloc分配内存的时候,系统底层一次为应用分配33块小内存,每块大小4k。

malloc从中取出自己需要的内存空间大小,如果系统提供的内存空间不够,再一次提供33块。释放时,如果33块全部没用时,就释放掉,当内存都释放完毕时,还会留用33块,以备下面语句/函数再次malloc。上层的malloc实现,使用的缓存技术,提高程序的运行效率。

malloc是库函数

 

二、            mmap内存映射

使用mmap系统调用将内存或者文件映射到虚拟地址空间

#include <sys/mman.h>

void *mmap(void *addr, size_t length, intprot, int flags, int fd, off_t offset);

功能:将内存或者文件映射到虚拟地址空间

参数:

addr :虚拟地址  (最好是由内核提供,一般为NULL,不需我们指定)  

length:映射的长度

prot:

PROT_EXEC Pages may be executed.  映射的页可被执行

PROT_READ Pages may be read.    映射页可读

PROT_WRITE Pages may be written.   映射页可写

PROT_NONE Pages may not be accessed.   映射页可被访问

flags:

 MAP_SHARED   共享的

  MAP_PRIVATE   私有的

  MAP_ANONYMOUS  匿名映射  :将内存映射到虚拟地址。fd和offset设置成0

fd:  文件描述符

offset:在文件中的偏移位置

返回值:

正确:返回被映射到的虚拟地址

错误:MAP_FAILED,并且errno被设置

 

int munmap(void *addr, size_t length);

参数:

addr :mmap系统调用的返回值

length :同mmap参数

功能:解除映射

举例:内存到虚拟地址的映射

mmap.c

  1#include<stdio.h>

  2#include<errno.h>

  3#include<sys/mman.h>

  4#include<string.h>

  5int main(int argc,char *argv[]){

 6     //地址由内核自动选择,长度20(页的20个字节)

 7     //字节只是映射内存,

 8     void *handle=mmap(NULL,20,\

 9            PROT_READ|PROT_WRITE,\

 10            MAP_PRIVATE|MAP_ANONYMOUS,0,0);

 11    //映射失败处理

 12    if(MAP_FAILED==handle){

 13        perror("map");

 14         return 1;

 15     }

 16    char *p=(char *)handle;

 17    strcpy(p,"tarena");

 18    printf("%s\n",p);

 19    //解除映射

 20    munmap(handle,20);

 21    return 0;

 22 }

 

三、            文件的操作

以前使用的fopen、fclose、fread、fwrite。。。 这些操作文件的函数都是库函数

使用系统调用进行文件的操作

文件有两种类型:文本文件(ASCII码文件)、二进制文件

以前学的是库函数,现在是系统调用

补充:

1、 linux 下一切皆文件

-rw-rw-r-- 1 tarena tarena  554  8月 31 11:53 mmap.c

drwxrwxr-x 2 tarena tarena     4096 8月 31 14:16day25

crw-rw-rw- 1 root toot     

第一个字符代表文件类型:

-         普通文件 

d  文件夹文件

c  字符车陂文件

b  块设备文件

l  软连接文件

2、什么是文件描述符?

3、进程的管理

Linux是多用户多任务的操作系统,多任务的本质就是多个进程同时进行。

操作系统需要管理多个进程。具体管理如下:

pid (process id ) 进程的id

PCB(process control block)进程控制块,存储的是这个进程的所有信息

字段描述该进程打开的所有文件

struct PCB{

       …..

       structfile *arr ;

       ……

};

arr指向了一个数组,数组的元素是指针类型

当用户打开一个文件时,内核自动给分配一块sizeof (struct file)大小的空间,指针数组的一个元素指向这块内存空间,然后这个指针数组那个元素的下标(从3开始)被返回,就是这个文件的文件描述符

4、 阻塞

等着条件的满足,程序可以继续执行。等待的过程就是阻塞

5、 文件权限

-rw-rw-r-- 1 tarena tarena  554  8月 31 11:53 mmap.c

drwxrwxr-x 2 tarena tarena     4096 8月 31 14:16day25

rwx rwx rwx

111,111,111

0,7 ,7,7

例:

0644   rw-r- -r- -

0755  rwxr-xr-x

6、umask 权限掩码

tarena@tarena-virtual-machine:~/day25$touch  text.txt

-rw-rw-r-- 1 tarena tarena    0  8月 31 15:26 text.txt

tarena@tarena-virtual-machine:~/day25$umask

0002

0002 对应  - - - - - - - w -

  (掩码)去掉w

tarena@tarena-virtual-machine:~/day25$umask 0033

tarena@tarena-virtual-machine:~/day25$touch tang.txt

tarena@tarena-virtual-machine:~/day25$ ls-l

-rw-r--r-- 1 tarena tarena    0  8月 31 15:32 tang.txt

 

 

系统调用函数

 

man 2 open

open  ( 2 )

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char *pathname, int flags);

int open(const char *pathname, int flags,mode_t mode);

功能:打开或者创建一个文件或设备

参数:

pathname:路径名

flags:

flags必须包含O_RDONLY(只读) 、O_WRONLY(只写)、P_RDWR(读写) 其中之一

可以按位或的标记:

O_CREAT:如果这个文件不存在,则创建这个文件

O_TRUNC:如果文件存在时,将文件里的内容清空,文件不存在,则创建文件,与O_CREAT结合使用

O_APPEND:追加到文件末尾

O_NONBLOCK:非阻塞 

mode:创建新文件的时候,需要使用mode给定新文件的权限

返回值:文件描述符

如果返回值为-1,代表出错,errno被设置

 

 

close  ( 2 )

#include <unistd.h>

int close(int fd);

参数:fd  open函数返回的文件描述符的值

返回值:返回0则成功,返回-1表示错误,errno被设置

举例:

touch text.txt   写入hello

1、以只读方式打开文件(file1.c)

  1#include<stdio.h>

  2#include<errno.h>

  3#include<fcntl.h>

  4#include<sys/types.h>

  5#include<sys/stat.h>

  6#include<unistd.h>

  7int main(int argc,char *argv[]){

 8     int fd;

 9     //以只读方式打开文件

 10    fd=open("a.txt",O_RDONLY);

 11    if(fd==-1){

 12        perror("open");

 13        return 1;

 14     }

 15    //关闭文件

 16    close(fd);

 17    return 0;

 18 }

open: No such file or directory

若fd=open("text.txt",O_RDONLY);  则成功   (本层路径有text.txt ,没有a.txt)

2、以只写的方式打开文件text.txt    file2.c

  1#include<stdio.h>

  2#include<errno.h>

  3#include<fcntl.h>

  4#include<sys/types.h>

  5#include<sys/stat.h>

  6#include<unistd.h>

  7int main(int argc,char *argv[]){

 8     int fd;

 9     //以只写方式打开文件

 10    fd=open("text.txt",O_WRONLY);

 11    if(fd==-1){

 12        perror("open");

 13        return 1;

 14     }

 15    printf("open file success\n");

 16    //关闭文件

 17    close(fd);

 18    return 0;

 19 }

如果文件不存在,报错

如果文件存在,打开成功,不对文件内容做更改

3、基于flie2.c的代码,打开的时候,如果文件不存在,创建文件,如果文件存在,则将文件内容清空   file3.c

  1#include<stdio.h>

  2#include<errno.h>

  3#include<fcntl.h>

  4#include<sys/types.h>

  5#include<sys/stat.h>

  6#include<unistd.h>

  7int main(int argc,char *argv[]){

 8     int fd;

 9     //以只写方式打开文件,如果文件不存在,创建文件,如果文件存在,清0

 10    fd=open("text.txt",O_WRONLY|O_CREAT|O_TRUNC,0644);

 11    if(fd==-1){

 12        perror("open");

 13        return 1;

 14     }

 15    printf("open file success\n");

 16    //关闭文件

 17    close(fd);

 18     return 0;

 19 }

tarena@tarena-virtual-machine:~/day25$ cattext.txt

hello

tarena@tarena-virtual-machine:~/day25$ gccfile3.c

tarena@tarena-virtual-machine:~/day25$./a.out

open file success

tarena@tarena-virtual-machine:~/day25$ cattext.txt    (text.txt的内容hello被清0)

tarena@tarena-virtual-machine:~/day25$ ls-l text.txt

-rw-rw-r-- 1 tarena tarena 0  8月 31 16:38 text.txt   (权限是0664,因为文件刚创建时的权限就是0664,在文件中虽然设置0644,但不改变,如果创建新的文件a.text,则权限就是0644)

 

 

read  ( 2 )

#include <unistd.h>

ssize_t read(int fd, void *buf, size_tcount);

功能:从参数fd指定的文件描述符中读取内容,读取count个字节,读取内容到buf指定的空间。

参数:

fd :open函数执行成功的返回值

count:读取字节的个数

buf:读取内容到buf指定的空间地址

返回值:

-1:代表错误  errno被设置

正常则返回读取到的个数

举例:使用read读取文件的内容,将读取的内容输出到屏幕

vi text.txt   one-dream-one-world-

read.c

  1#include<stdio.h>

  2#include<errno.h>

  3#include<fcntl.h>

  4#include<sys/types.h>

  5#include<sys/stat.h>

  6#include<unistd.h>

  7int main(int argc,char *argv[]){

 8     int fd,ret;

 9     char buf[20]={0};

 10    //以只读方式打开文件

 11    fd=open("text.txt",O_RDONLY);

 12    if(fd==-1){

 13        perror("open");

 14        return 1;

 15     }

 16    printf("open file success\n");

 17    //从文件都去内容到buf空间

 18    read(fd,buf,10);

 19    ret=read(fd,buf,10);

 20    if(ret==-1){  //读取失败

 21        perror("read");

 22        return 2;

 23     }

24    printf("%s\n",buf);

 25    //关闭文件

 26    close(fd);

 27    return 0;

 28 }

执行结果

tarena@tarena-virtual-machine:~/day25$./a.out

open file success

one-world-

 

作业:1、写一个程序完成cat命令的功能。mycat

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值