C/C++学习笔记——环境变量及内存管理

date 2020.07.08

环境变量

1.访问环境变量表

#include<stdlib.h> //加载库

通过env命令可以查看当前shell进程的环境变量

子进程在默认环境下继承其父进程的环境变量

2.访问特定环境

#include<stdlib.h> //加载库

a.char* getenv(char const* name); 根据环境变量名称获取该变量的值

成功返回与参数匹配的环境变量的值,失败返回NULL;
       name :环境变量名

b.int putenv(char* string); 增加新的环境变量或修改已有环境变量的值;

成功返回0;失败返回非0;

string:形如“变量名 = 变量值”形式的字符串。(变量名存在为修改变量值,不存在为新增变量值)

int setenv(char const* name,char *const value ,int overwrite);

name :环境变量名

value:环境变量值

overwrite:当所给环境变量名已存在时(存在为1;反之为0)是否覆盖原值;

c. int unsetenv(char const* name); 删除环境变量;

成功返回0;失败返回-1。

name :环境变量名

int clearenv(void); 清除所有环境变量,同时将environ置NULL。

成功返回0;失败返回非0。

示例代码

/*
    date 2020-07-07
    version 1.0
    name 环境变量操作演示
*/
#include<stdio.h>
void penv(char* ppc) {
    printf("---------环境变量----\n");
    while(ppc && *ppc)
        printf("%s\n",*ppc++);
    printf("---------------------\n");
}
int main(int argc ,char* argv[] ,char* env[]) {
    extern char** environ;
    penv(environ);
    penv(env);
    printf("%p%p\n",environ ,env);
    printf("%s\n",getenv("PATH"));
    putenv("STUDENT=MYNAME");
    penv(environ);
    putenv("STUDENT=YOURNAME");
    penv(environ);
    setenv("CITY","Chengdu",0);
    penv(environ);
    setenv("CITY","Sanya",0);
    penv(environ);
    setenv("CITY","Sanya",1);
    penv(environ);
    unsetenv("CITY");
    penv("environ");
    clearenv();
    penv(environ);
    printf("%p\n",environ);
    return 0;
}

 

 

 


内存管理:内存分配与释放

1.内存分配和释放方式

a. void foo(void) {

    int a; // 自动分配,自动释放

    ..... 

    }

b. void bar(void){

    int *b = (int*)malloc(sizeof(int));  //手动分配,动态释放

    ...

   free(b)

}

2.应用程序: 业务逻辑对内存资源的使用

STL:代表不同数据结构标准容器

C++:new/delete

C:malloc/calloc/realloc/free

POSIX:sbrk/brk

系统内核:mmap/munmap

系统底层:kalloc/vmalloc

硬件驱动:get_free_page

硬件设备:硬件指令集

虚拟内存

1.虚拟内存

 虚拟内存的本质就是一个地址范围,用于在应用程序中访问储存空间,但实际存放的数据是物理内存,物理内存和虚拟内存之间存在动态的对应关系,称之为内存映射。

32机器的地址范围:0 ~ 4G-1

内存壁垒

每个进程的地址空间可被划分为内核空间和用户空间两部分,其中内核空间共享同一个物理内存区域,而用户空间映射到不同的物理内存区域,这就是进程间的内存壁垒。

2.段错误

SIGSEGV(11)

    试图访问没有映射到物理内存的虚拟内存

    试图已以非法方式访问虚拟内存,如对只读内存写操作

/*
    date 2020-07-09
    name 段错误操作演示
    version 1.0*/
#include<stdio.h>
#include<stdlib.h>
int main(void) {
    int* p = malloc(sizeof(int));
    printf("%p\n",p);
    *p = 1234;
    printf("%p\n",*p);
    free(p);
    }

a.以相对方式分配和释放虚拟内存

#include<unistd.h>

void* sbrk(intptr_t increment);

成功返回调用该函数前的堆尾指针,失败返回-1.

increment:堆内存的字节增量(> 0 分配内存; < 0 释放内存; = 0 当前堆尾)

堆尾指针

堆空间最后一个被分配字节的下一个字节的地址

示例代码

/*
    date 2020-07-09
    name sbrk操作演示;
    version 1.0
 */
#include<stdio.h>
#include<unistd.h>
int main(void) {
    int* p1 = sbrk(sizeof(int));
    *p1 = 123;
    double* p2 = sbrk(sizeof(double));
    *p2 = 4.56;
    char* p3 = sbrk(sizeof(char) * 256);
    sprintf(p3,"Hello ,World");
    printf("%d %g %s\n,*p1,*p2,p3");
    return 0;
    }

b.以绝对方式分配和释放虚拟内存

int brk(void* end_data_segment)

成功返回0 ,失败返回-1

end_data_segment 堆尾指针的目标位置(> 堆尾指针的目标位置 分配内存 ;< 堆尾指针的目标位置 释放内存 ;= 堆尾指针的目标位置 空操作)

示例代码

/*
    date 2020-07-09
    name brk操作演示
    version 1.0
*/
#include<stdio.h>
#include<unistd.h>
int main(void) {
    setbuf(stdout NULL);
    printf("%p\n",sbrk(0));
    int* p1 = sbrk(sizeof(int));
    *p1 = 123;
    double* p2 = sbrk(sizeof(double));
    *p2 = 4.56;
    char *p3 = sbrk(sizeof(char) * 256);
    sprintf(p3 ,"Helle ,World");
    printf("%d %g %s\n",*p1 ,*p2,p3);
    //sbrk(-(sizeof)(int) + sizeof(doyuble) + sizeof((char) * 256));
    brk(p1);
    printf("%p\n",sbrk(0));
    return 0;
}

 

c.用sbrk 分配内存 ,用brk释放内存;

3.mmap 和 munmap 函数

a.建立虚拟内存到物理内存或磁盘文件的映射

#include<sys/mman.h>

void* mmap(void * start ,size_t length,int prot ,int flags,int fd ,off_t offset);

成功返回映射区虚拟内存的起始地址,失败返回MAP_FAILED(-1).

start :映射区虚拟内存的起始地址,NULL系统自动选定后返回;

length:映射区字节数,自动按页圆整;

port:映射区操作权限(PROT_READ 读 PROT_WRITE 写 PORT_EXEC 执行 PORT_NONE 不可访问);

flags: 映射标志

    MAP_ANONYMOUS   |   MAP_PRIVATE 虚拟内存到物理内存的映射;

    MAP_SHARED 虚拟内存到磁盘文件的映射;

fd:文件描述符;

offset:文件偏移量 ,自动按页对齐。

b.解除虚拟内存到物理内存或磁盘文件的映射

#include<sys/mman.h>

void* munmap(void * start ,size_t  length);

start :映射区虚拟内存的起始地址,

length:映射区字节数,自动按页圆整;

示例代码

/*
 date 2020-07-09
 name manmap操作演示
 version 1.0
*/
int main(void) {
    char* p = mmap(NULL,8192,PORT_READ | PORT_WRITE,MAP_ANONTMOUS | MAP——PRIVATE,0,0);
    if(P1 == MAP_FAILED) {
        perror)("mmap");
        return -1;
    }
    strcpy(p1,"第一个内存页");
    print("%p\n",p1);
    if(munmap(p1,4096) == -1) {
        perror)("mmap");
        return -1
    }
    printf("%s\n",p1);
    char* p2 = p1 + 4096;
    strcpy(p1,"第二个内存页");
    print("%p\n",p1);
    if(munmap(p1,4096) == -1) {
        perror)("mmap");
        return -1
    }
    //printf("%s\n",p2);
    return 0;
}

系统调用

应用程序的层次结构

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值