[Linux 进程(四)] 再谈环境变量,程序地址空间初识

文章目录
- 1、前言
- 2、环境变量
- 2.1 main函数第三个参数 -- 环境参数表
- 2.2 本地环境变量和env中的环境变量
- 2.3 配置文件与环境变量的全局性
- 2.4 内建命令与常规命令
- 2.5 环境变量相关的命令
- 3、程序地址空间
1、前言
上一篇我们讲了环境变量,如果有不明白的先读一下上一篇文章:环境变量讲解
本篇文章我们继续完善环境变量这章剩下的内容,以及main函数第三个参数的详解,进程地址空间的初始。
2、环境变量
2.1 main函数第三个参数 – 环境参数表
看完上一篇文章的同学,肯定知道了如何查看环境变量,命令行输入 env:
我们查看一下:

我们main函数的参数列表中,第三个就是环境变量表,没错它里面就记录着这些环境变量。
它与第二个参数一样,都是char类型的指针数组。我们写一段代码,打印一下环境变量表中的内容:
#include <stdio.h>int main(int argc, char* argv[], char* env[])
{int i = 0;for( ; env[i]; i++){printf("env[i]: %s\n", i, env[i]);}return 0;
}

我们发现main函数的第三个参数,环境参数表跟我们env所查出来的内容是一模一样的。
这是因为我们程序在运行时,环境变量是系统给传的。
问题:
那这个给程序传环境变量的系统是谁?
在学习fork的时候,我们知道fork()函数是可以创建子进程的。同时我们也知道命令行启动的进程都是shell/bash的子进程,子进程的命令行参数和环境变量,是父进程bash给传递的!
问题:
那父进程bash的环境变量信息又是从哪里来的?
我们在上一篇中讲到,PATH内容修改后,下一次启动Xshell时,PATH内容又自动恢复了。这其实是我们直接更改了bash进程内部的环境变量信息!
每一次重新登录,都会给我们形成新的bash解释器并且新的bash解释器自动从 哪里 读取自己的环境变量表信息!
虽然我们现在还不知道父进程环境变量哪里来的,但是环境变量存在哪我就直接说了:环境变量信息是以脚本配置文件的形式存在的!
在登录目录下有一个.bash_profile脚本文件,每一次登录的时候,bash进程都会读取 .bash_profile配置文件中的内容,为我们bash形成一张环境变量表信息!

2.2 本地环境变量和env中的环境变量
我们可以在bash中直接定义环境变量:环境变量名 = 内容
我们来试一下:

用户定义的环境变量是本地的,env是查看不了本地环境变量的。

如果我们想要把我们自己定义的环境变量,导出到env所能查看到的环境变量中,我们可以使用以下命令:
export 环境变量名

还可以直接使用export定义环境变量:

当我们把自己定义的环境变量放入了bash的环境变量后,我们在main函数所打印的环境变量中能不能找到呢,我们试一下:

我们在命令行中输入的命令都是bash的子进程,这就验证了子进程的环境变量是由父进程给传递的。
2.3 配置文件与环境变量的全局性
问题:
我们要是重新登录Xshell的话,我们刚导出的环境变量还在吗?
在不在我们测试一下就出来了:

明显是不在的,我们刚才导出是直接给bash进程的内部导出了。我们重新启动后 .bash_profile脚本文件会重新执行,bash进程内部的环境变量会重新读取并形成一份新的环境变量表。
如果我们想要每次登录后,bash的环境变量表都有我们自己添加的环境变量,我们就需要在 .bash_profile脚本文件中添加,此后再登录后bash的环境变量表中就有了添加的环境变量。


我们再介绍一个获取环境变量的系统调用函数,const char ** environ

我们发现environ的类型是一个二级指针,这里不卖关子了,它其实指的是环境变量表首元素:

我们写一段代码将其内容打印出来:
#include <stdio.h>
#include <unistd.h>int main()
{extern char** environ;int i = 0;for(i = 0; environ[i]; i++){printf("environ[%d]: %s\n", i, environ[i]);}return 0;
}

问题: 大家有没有想过,如果我们本地环境变量,子进程会将我们添加的本地环境变量也继承下来吗?
我们做一下实验:

显然是没有的(这里细心的人会发现echo为什么就继承下来了,其实echo不是子进程,别急下一个话题我们就会讲到)。如果我们将本地变量导出到系统环境变量中,子进程就会将其继承下来。
总结:
1、迄今为止我们学到了三种获取环境变量的方式:
- getenv();
- main函数传参方式;
- extern char** environ;
2、bash再去创建子进程时,bash会给子进程传递一份同样的环境变量,子进程再创建子进程天然的就继承了父进程的环境变量表,也就间接获取了bash所传递的环境变量,所以系统环境变量具有全局属性!
3、本地环境变量 vs 系统环境变量
- 本地环境变量只在bash进程内部有效,不会被子进程继承下去;
- 系统环境变量通过让所有子进程继承的方式,实现自身的全局性!
2.4 内建命令与常规命令
通过上一篇的学习,我们知道了,bash自己的指令可以直接使用,不用加 ./,因为这些指令在系统默认路径PATH下,现在我们将PATH置空,这些指令就运行不了了!

我们发现,有些指令确实不能运行了,但是有些指令仍然可以运行。这是为什么呢?
Linux下命令分为两类:
- 常规命令:shell通过fork创建子进程,让子进程执行的;
- 内建命令:shell命令行的一个函数。
原来pwd,echo都是内建命令。
那为什么内建命令就直接能读取环境变量呢?
内建命令是shell内部的一个函数,父进程内部执行,它是可以直接看到父进程内部的,当然可以直接读取shell内部定义的本地变量!
2.5 环境变量相关的命令
- echo: 显示某个环境变量值
- export: 导出一个新的环境变量
- env: 显示所有环境变量
- unset: 清除环境变量
- set: 显示本地定义的shell变量和环境变量

3、程序地址空间
C/C++程序员认为,程序内存分布是这样子的:

我们写一段代码验证一下:
#include <stdio.h>
#include <stdlib.h>int uninit_global;
int init_global = 0;
int main(int argc, char* argv[], char* env[])
{printf("code address: %p\n", main); // 代码区const char* str = "Hello Linux!\n";printf("read only char address: %p\n", str); // 字符常量区printf("init global value address: %p\n", &init_global);printf("uninit global value address: %p\n", &uninit_global);char* heap1 = (char*)malloc(sizeof(char)*100);char* heap2 = (char*)malloc(sizeof(char)*100);char* heap3 = (char*)malloc(sizeof(char)*100);char* heap4 = (char*)malloc(sizeof(char)*100);static int a = 0;printf("heap1 address: %p\n", heap1); printf("heap2 address: %p\n", heap2);printf("heap3 address: %p\n", heap3);printf("heap4 address: %p\n", heap4);printf("stack address: %p\n", &str);printf("stack address: %p\n", &heap1);printf("stack address: %p\n", &heap2);printf("stack address: %p\n", &heap3);printf("stack address: %p\n", &heap4);printf("a address: %p\n," &a);int i = 0;for(i = 0; i < argc; i++){printf("argv[%d]: %p\n", i, argv[i]);}for(i = 0; env[i]; i++){printf("env[%d]: %p\n", i, env[i]);}return 0;
}

我们在这里就能看出来:
1、堆上的地址内存的使用是不断增大;
2、栈上的地址内存的使用是不断减小的,但是在我们c/c++中,定义数组、结构体或者整型,它们的地址是向上增长的。比如,开辟一个十个元素的整型数组,一次整体开出来,首元素地址在最低,因此遍历时是++操作。
3、static修饰的静态成员变量,其实就是全局变量,他就放在已初始化全局变量区,所以它在全局就一份。
4、栈区之上先是命令行参数,再是环境变量,不断向上增上的。
相关文章:
[Linux 进程(四)] 再谈环境变量,程序地址空间初识
文章目录 1、前言2、环境变量2.1 main函数第三个参数 -- 环境参数表2.2 本地环境变量和env中的环境变量2.3 配置文件与环境变量的全局性2.4 内建命令与常规命令2.5 环境变量相关的命令 3、程序地址空间 1、前言 上一篇我们讲了环境变量,如果有不明白的先读一下上一…...
【C++】STL(标准模板库)
文章目录 1. 基本概念2. 容器2.1. 容器的分类2.2. vector2.2.1. 构造vector对象2.2.2. vector的赋值 1. 基本概念 STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称,现在已经成为C标准库的重要组成部分。STL的…...
【已解决】fatal: Authentication failed for ‘https://github.com/.../‘
文章目录 异常原因解决方法 异常原因 在 Linux 服务器上使用git push命令,输入用户名和密码之后,总会显示一个报错: fatal: Authentication failed for https://github.com/TianJiaQi-Code/Linux.git/ # 致命:无法通过验证访问起…...
SqlAlchemy使用教程(二) 入门示例及编程步骤
SqlAlchemy使用教程(一) 原理与环境搭建SqlAlchemy使用教程(三) CoreAPI访问与操作数据库详解 二、入门示例与基本编程步骤 在第一章中提到,Sqlalchemy提供了两套方法来访问数据库,由于Sqlalchemy 官方文档结构有些乱,对于ORM的使用步骤的描…...
HTML+JS+CSS移动端购物车选购界面
代码打包资源下载:【免费】HTMLJSCSS移动端购物车选购界面资源-CSDN文库 关键部分说明: UIGoods 类: 构造函数: 创建 UIGoods 实例时,传入商品数据 g,初始化商品的数据和选择数量。getTotalPrice() 方法…...
微服务治理:为什么要分析微服务的依赖关系?
在微服务架构中,单个服务相互协作以交付功能。这些协作会在服务之间形成依赖关系,其中一个服务依靠另一个服务来完成自己的任务。虽然依赖关系使功能得以实现,但不受控制的依赖关系可能会导致一系列挑战: 复杂性: 错综复杂的依赖…...
【程序员的自我修养—系统调用与API】
系统调用 背景: 为了避免有限的系统资源被多个不同的应用程序同时访问,需要加以保护,避免冲突;提供一套统一的接口,是应用程序能做一些由操作系统支持的行为;接口通过中断的方式实现,Linux使用…...
使用宝塔面板部署后端项目到服务器
文章目录 前言第一步:安装数据库第二步:打包后端项目第三步:配置数据库第四步:部署后端项目第五步:前后端联调测试总结 前言 在之前我已经写了一篇如何去部署前端项目,虽然能访问网站,但是没有…...
走迷宫(c语言)
前言: 制作一个迷宫游戏是一个有趣的编程挑战。首先,我们需要设计一个二维数组来表示迷宫的布局,其中每个元素代表迷宫中的一个格子。我们可以使用不同的值来表示空格、墙壁和起点/终点。接下来,我们需生成迷宫。在生成迷宫的过程…...
两周掌握Vue3(五):自定义指令、路由、ajax
文章目录 一、自定义指令1.创建和使用自定义指令2.钩子函数3.使用参数 二、路由1.创建一个router实例2.在components目录中创建组件3.将路由实例挂载到应用4.使用路由 三、Ajax 代码仓库:跳转 当前分支:05 一、自定义指令 自定义指令是Vue.js框架提供的…...
redis之单线程和多线程
目录 1、redis的发展史 2、redis为什么选择单线程? 3、主线程和Io线程是怎么协作完成请求处理的? 4、IO多路复用 5、开启redis多线程 1、redis的发展史 Redis4.0之前是用的单线程,4.0以后逐渐支持多线程 Redis4.0之前一直采用单线程的主…...
12AOP面向切面编程/GoF之代理模式
先看一个例子: 声明一个接口: // - * / 运算的标准接口! public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j); }实现该接口: package com.sunsplanter.prox…...
【MySQL】数据处理之增删改
文章目录 一、增加(插入)INSERT INTO...VALUES(...,...)VALUES的方式添加情况一:为表的所有字段按默认顺序插入数据情况二:为表的指定字段插入数据情况三:同时插入多条记录 将查询结果插入到表中 二、修改(…...
利用docker的LNMP
目录 服务器环境 任务需求 服务搭建 Nginx Mysql Php 启动 wordpress 服务 服务器环境 容器 操作系统 IP地址 主要软件 nginx CentOS 7 172.20.0.10 Docker-Nginx mysql CentOS 7 172.20.0.20 Docker-Mysql php CentOS 7 172.2…...
Grafana(二)Grafana 两种数据源图表展示(json-api与数据库)
一. 背景介绍 在先前的博客文章中,我们搭建了Grafana ,它是一个开源的度量分析和可视化工具,可以通过将采集的数据分析、查询,然后进行可视化的展示,接下来我们重点介绍如何使用它来进行数据渲染图表展示 Docker安装G…...
Shape-IoU——综合考量边框形状与尺度的度量
今天看到一篇文章主要是提出了一种更有效的IOU度量方法,论文地址在这里,如下所示: 摘要 边界盒回归损失作为检测器定位分支的重要组成部分,在目标检测任务中起着重要作用。现有的边界框回归方法通常考虑GT框和预测框之间的几何关…...
Stack详解(Java)
Stack Java 中的 Stack 是一种基于后进先出(LIFO)原则的数据结构。Stack 类实现了一个标准的堆栈,它继承自 Vector 类,并提供了一些额外的方法来支持堆栈的操作。 下面是一些 Java Stack 类的详细解释: 构造方法&…...
Qt框架学习 --- CTK编译(Qt5.15.2+vs2019+cmake)
系列文章目录 第二章 CTK的测试demo https://blog.csdn.net/yonug1107716573/article/details/135527289 文章目录 系列文章目录前言一、准备工作二、编译步骤1.修改文件2.编译CTK2.1 准备2.2 cmake界面配置2.3 配置编译器2.4 编译的配置设置2.5 选择需要编译的模块2.6 生成2.…...
Flink(十三)【Flink SQL(上)】
前言 最近在假期实训,但是实在水的不行,三天要学完SSM,实在一言难尽,浪费那时间干什么呢。SSM 之前学了一半,等后面忙完了,再去好好重学一遍,毕竟这玩意真是面试必会的东西。 今天开始学习 Flin…...
linux nginx配置链接访问图片
nginx 安装 sudo apt update sudo apt install nginxnginx 启动命令 sudo systemctl restart nginx # 重启 sudo systemctl start nginx #开启 sudo systemctl stop nginx # 关闭 sudo systemctl status nginx # 状态 sudo systemctl restart nginx.service #重启nginx安装成…...
Huey终极指南:为什么这个轻量级Python任务队列成为开发者的首选?
Huey终极指南:为什么这个轻量级Python任务队列成为开发者的首选? 【免费下载链接】huey a little task queue for python 项目地址: https://gitcode.com/gh_mirrors/hu/huey 在Python开发世界中,高效处理异步任务和定时任务是提升应用…...
Zotero插件安装失败?手把手教你解决版本兼容问题(以better-notes为例)
Zotero插件安装失败?手把手教你解决版本兼容问题(以better-notes为例) 学术研究离不开文献管理工具,Zotero作为开源免费的文献管理神器,凭借其强大的功能和丰富的插件生态,成为众多科研工作者的首选。然而…...
硬件工程师的‘工具箱’进化史:从万用表到示波器,再到我离不开的5款效率神器
硬件工程师的效率革命:5款改变工作流的现代工具解析 十年前,我的工作台上堆满了各种笨重的测试设备,笔记本里塞满手绘的电路图和潦草的调试记录。如今,当我走进新一代硬件工程师的实验室,发现他们的工作方式已经发生了…...
sklearn分类报告报错?一招解决UndefinedMetricWarning的零除问题
机器学习模型评估中的UndefinedMetricWarning:从原理到实战解决方案 当你第一次看到控制台弹出"UndefinedMetricWarning: Precision and F-score are ill-defined"的红色警告时,是不是感觉一头雾水?这个看似简单的警告背后&#x…...
虚拟机自动化新范式:CUA Computer SDK十分钟入门指南
虚拟机自动化新范式:CUA Computer SDK十分钟入门指南 【免费下载链接】cua Create and run high-performance macOS and Linux VMs on Apple Silicon, with built-in support for AI agents. 项目地址: https://gitcode.com/GitHub_Trending/cua/cua 在当今的…...
电感器特性与工程应用全解析
电感器的工程应用与特性分析1. 电感器基础特性电感器(Inductor)是电子电路中的基本无源元件,由导线绕制而成,可分为空心线圈和带磁芯线圈两种基本结构。其基本单位是亨利(H),常用单位还包括毫亨(mH)和微亨(μH),换算关系为&#x…...
LingBot-Depth部署教程:Docker Compose编排+模型缓存卷自动初始化
LingBot-Depth部署教程:Docker Compose编排模型缓存卷自动初始化 1. 引言:从稀疏数据到精准3D测量 你有没有遇到过这样的场景?手头有一个深度摄像头,但采集到的深度图总是零零散散,像一张被撕破的旧地图,…...
AVR微控制器通用驱动库VitconCommon详解
1. VitconCommon 库概述VitconCommon 是一个面向 AVR 微控制器平台的底层通用函数库集合,由 Vitcon 团队开发并维护,作为其系列外设驱动库(如 VitconGP2Y0A21YK、VitconSAA1064T 等)的公共依赖基础。该库不提供独立的应用层功能&a…...
3步实现Axure RP本地化界面优化:开源工具助力中文设计环境构建
3步实现Axure RP本地化界面优化:开源工具助力中文设计环境构建 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包,不定期更新。支持 Axure 9、Axure 10。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-c…...
5大维度解析Mac Mouse Fix:从工具到体验的蜕变之旅
5大维度解析Mac Mouse Fix:从工具到体验的蜕变之旅 【免费下载链接】mac-mouse-fix Mac Mouse Fix - A simple way to make your mouse better. 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix Mac Mouse Fix是一款让普通鼠标在macOS系统上…...
