回顾昨天内容:
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