C语言字符串处理及内存管理函数

    0x00

    这一节,我们介绍下常用的C语言字符串处理函数和内存管理函数。


    0x01

    字符串处理函数:

    strstr:返回字符串中首次出现子串的地址

    详解地址:http://c.biancheng.net/cpp/html/174.html

    strchr:查找某字符在字符串中首次出现的位置
    详解地址: http://c.biancheng.net/cpp/html/161.html
    strncpy:复制字符串的前n个字符
    详解地址: http://c.biancheng.net/cpp/html/170.html
    strncat:在字符串的结尾追加n个字符
    详解地址: http://c.biancheng.net/cpp/html/169.html
    strcpy:复制字符串
    详解地址: http://c.biancheng.net/cpp/html/164.html
    strcat:连接字符串
    详解地址: http://c.biancheng.net/cpp/html/160.html
    strlen:返回字符串的长度
    详解地址: http://c.biancheng.net/cpp/html/167.html
    strcmp:比较字符串(区分大小写)
    详解地址: http://c.biancheng.net/cpp/html/162.html
    注意:上面例子中多次用到字符数组和字符串。 字符数组是可以被修改的,字符串是只读的,不能被修改

    0x02
    内存管理函数:
    memset:将内存的前n个字节设置为特定的值
    详解地址: http://c.biancheng.net/cpp/html/157.html
    memcpy:复制内存内容(忽略\0)
    详解地址: http://c.biancheng.net/cpp/html/155.html。与 strcpy() 不同的是,memcpy() 会完整的复制 num 个字节,不会因为遇到“\0”而结束。

    0x03
    下面我们重点讲一下内存管理函数mmap:
#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: 映射区可被执行.
    • PROT_READ: 映射区可被读取.
    • PROT_WRITE: 映射区可被写入.
    • PROT_NONE: 映射区不能存取.
  • flags: 映射区的特性, 可以是:
    • MAP_SHARED: 对映射区域的写入数据会复制回文件, 且允许其他映射该文件的进程共享.
    • MAP_PRIVATE: 对此区域所做的修改不会写回原文件, 且不允许其他映射该文件的进程共享.
    • MAP_ANONYMOUS:匿名创建映射区域, fd为-1, offset为0.
    • MAP_FIXED:后面介绍
  • fd: 由open返回的文件描述符, 代表要映射的文件.
  • offset: 以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射.

    返回值为映射后的虚拟地址:
    1、如果addr为NULL,那么这个虚拟地址由系统指定。
    2、如果addr不为NULL,并且flag不为MAP_FIXED,那么最后分配的虚拟地址尽量与设置的值相近。
    3、如果addr不为NULL,并且flag为MAP_FIXED,那么最后分配的虚拟地址必须和addr保持一致,否则出错。
  
    length为要映射的文件内容大小,如果大小大于4096(一页),小于8192(两页),那么会分配两页的内存。
    如果大小不是页的整倍数,具体分三种情况来讨论:
    情形一:一个文件的大小是5000字节,mmap函数从一个文件的起始位置开始,映射5000字节到虚拟内存中。 
    分析:因为单位物理页面的大小是4096字节,虽然被映射的文件只有5000字节,但是对应到进程虚拟地址区域的大小需要满足整页大小,因此mmap函数执行后,实际映射到虚拟内存区域8192个 字节,5000~8191的字节部分用零填充。映射后的对应关系如下图所示:
    
    此时:
    1、读/写前5000个字节(0~4999),会返回操作文件内容。 
    2、读字节5000~8191时,结果全为0。写5000~8191时,进程不会报错,但是所写的内容不会写入原文件中 。 
    3、读/写8192以外的磁盘部分,会返回一个SIGSECV错误。

    情形二:一个文件的大小是5000字节,mmap函数从一个文件的起始位置开始,映射15000字节到虚拟内存中,即映射大小超过了原始文件的大小。
    分析:由于文件的大小是5000字节,和情形一一样,其对应的两个物理页。那么这两个物理页都是合法可以读写的,只是超出5000的部分不会体现在原文件中。由于程序要求映射15000字节,而文件只占两个物理页,因此8192字节~15000字节都不能读写,操作时会返回异常。如下图所示:
    
    此时:
    1、进程可以正常读/写被映射的前5000字节(0~4999),写操作的改动会在一定时间后反映在原文件中。
    2、对于5000~8191字节,进程可以进行读写过程,不会报错。但是内容在写入前均为0,另外,写入后不会反映在文件中。
    3、对于8192~14999字节,进程不能对其进行读写,会报SIGBUS错误。
    4、对于15000以外的字节,进程不能对其读写,会引发SIGSEGV错误。

    情形三:一个文件初始大小为0,使用mmap操作映射了1000*4K的大小,即1000个物理页大约4M字节空间,mmap返回指针ptr。
    分析:如果在映射建立之初,就对文件进行读写操作,由于文件大小为0,并没有合法的物理页对应,如同情形二一样,会返回SIGBUS错误。
    但是如果,每次操作ptr读写前,先增加文件的大小,那么ptr在文件大小内部的操作就是合法的。
    例如,文件扩充4096字节,ptr就能操作ptr ~ [ (char)ptr + 4095]的空间。只要文件扩充的范围在1000个物理页(映射范围)内,ptr都可以对应操作相同的大小。 这样,方便随时扩充文件空间,随时写入文件,不造成空间浪费。
    关于mmap函数,更加详细的内容请参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值