Unix高级编程:malloc内存管理、缓冲机制、mmap内存映射到进程、系统调用文件操作

来源:互联网 发布:sql orderby limit 编辑:程序博客网 时间:2024/05/22 11:59
<面试题1>:"动态内存释放后打印"
    free(str); //释放掉后str指针不合法,所以需置空
    printf("%s\n", str); //打印结果不确定。
    str = NULL;
return 0;
<面试题2>:"悬空指针"
    int *p; //局部变量没有初始化 == 悬空指针
    *p = 10; //赋值错误,编译ok执行时段错误
错误示范1:
char *p; //悬空指针
*p = 'a'; //也是错误写法:段错误
错误示范2:
int *p = (int *)0x12345678;//编译警告,执行段错误,没有映射物理地址


一、malloc的内存管理
/*举例说明 代码参见 malloc.c*/  什么是缓冲/缓存??
第一次向系统申请分配动态内存 1024 个字节,但系统分配最少 33 块(4k/块),以 4k 为基本单位。
总共 33 * 4 == 132 k, 即 132 字节
十进制的 33 块 == 十六进制的 21 (16进制地址差)


缓存:
没有用完 132 字节的时候,还在该内存地址范围内分配使用
用完 132 字节的时候,系统重新分配新的 132 字节内存地址


缓冲机制


二、mmap直接将内存映射到进程的地址空间
"mmap"(2)
#include <sys/mman.h>  //包含单独的头文件
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
功能:将文件或设备映射到进程的地址空间里
参数:
"addr" 指定了映射的起始地址。如果为 NULL 这个地址由内核决定
"length" 指定了映射的长度
"prot" 
   PROT_EXEC  executed.//映射页可执行
   PROT_READ  read.//映射页可读
   PROT_WRITE written.//映射页可写
   PROT_NONE  not be accessed.//映射页不可以被访问
"flags"
MAP_SHARED Share.//可以被其他进程共享,更新的内容可以显示到其他进程和文件中
MAP_PRIVATE private.//不能被其他进程共享,更新的内容不能显示到文件里
MAP_ANONYMOUS //与根文件没有关系。映射的就是物理内存 anonymous
"fd" 文件描述符,暂用不着,是 0
"offset" 偏移量,暂用不着,是 0
返回值:
成功 - 返回一个指向映射区域的地址
失败 - 返回"MAP_FAILED",errno被设置


int munmap(void *addr, size_t length);
功能:解除映射
参数:
"addr" mmap(2)的返回值,就是映射内存的起始虚拟地址
"length" mmap(2)中映射的长度
返回值:
成功 - 返回 0
失败 - 返回 -1,errno被设置
/*举例验证,mmap映射物理内存到虚拟地址空间,代码 mmap.c */
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
int main(void) {
    //建立映射,物理内存到虚拟地址空间的映射
    void *p = mmap(NULL,1024,PROT_WRITE | PROT_READ, \
                    MAP_PRIVATE | MAP_ANONYMOUS,0,0);
    if(p == MAP_FAILED) { //映射失败
        perror("mmap");
        return 1;
    }   
    printf("mmap success...\n"); //映射成功
    strcpy(p, "hello,world!");
    printf("%s\n", (char *)p);
    //解除映射
    munmap(p, 1024);
    p = NULL;
    return 0;
} //编译时给定虚拟地址,命令行执行 nm a.out 在main函数T状态的地址即是




三、文件的操作
标准C  fopen  fclose  fread  fwrite ... FILE *fp;
UC  使用系统调用来操作文件


对文件操作的系统调用有:
"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);


int open(const char *pathname, int flags,...); //正确写法,真正原型
功能:打开一个文件,并返回一个文件描述符
参数:
"pathname" 文件路径
"flags" (以下 3 个选项,必须选择其 1)
O_RDONLY //只读方式打开文件
O_WRONLY //只写方式打开文件
O_RDWR   //可读可写方式打开文件


file creation flags //文件创建标记
O_CREAT //如果文件不存在,则创建文件。mode(文件权限)还需要指定
O_EXCL //需要和 O_CREAT 标记一起使用,如果文件不存在,则创建文件;如果文件存在,则函数调用失败
O_TRUNC //如果文件存在,将这个文件内容清0;如果不存在,就创建文件


file status flags //文件状态标记
O_APPEND //追加到文件末尾


"..." 代表"可变参数"
返回值:
成功 - 返回一个新的文件描述符
失败 - 返回-1,errno被设置 


文件权限??


补充:
1) "..." 可变参数,最常见的有 printf(2)
int printf(const char *format, ...); //...参数个数可变
2) "文件描述符"
进程打开的文件列表里数组的下标,就是文件描述符。
3)"什么是进程"?
程序是静态的,以文件的形势存放在磁盘上。
进程是动态的,程序运行起来叫做进程。
一个进程,是"一个程序运行的实例"。(每次运行对应一个新的pid)
操作系统怎么管理进程?
每个进程都有自己的身份证号(pid)
PCB(进程控制块),记录了进程运行时所有资源使用的情况


0 标准输入
1 标准输出
2 标准错误输出


"close"(2)
#include <unistd.h>
int close(int fd);
功能:关闭一个文件描述符
参数:"fd" open(2)函数的返回值。指定一个文件描述符
返回值:
成功 - 返回 0
失败 - 返回-1,errno被设置


/*举例验证文件的打开,以只读的方式打开hello.txt,代码参见 file.c*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
    int fd; 
    //打开文件hello.txt
    fd = open(argv[1], O_RDONLY); //使用命令行参数执行
    if(fd == -1) { //打开文件错误
        perror("open"); //设置errno
        return 1;
    }
    printf("open file success...\n");
    //关闭文件描述符
    close(fd);
    return 0;
}
0 0