Linux 环境变量 二
目录
获取环境变量的后两种方法
环境变量具有全局属性
内建命令
和环境变量相关的命令
c语言访问地址
重新理解地址
地址空间

获取环境变量的后两种方法
main函数的第三个参数 :char* env[ ]
也是一个指针数组,我们可以把它的内容打印出来看看。
#include<stdio.h> #include<stdlib.h> #include<string.h> E>int main(int argc,char* argv,char* env[]) { int i=0; for(; env[i];i++) {
E> printf("env[%d]:%s\n",i,env[i]); } return 0;
}
我们再把pid也打印出来看看:
输入命令:
!man getpid
我们把这两个头文件加上
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h>
E>#include<unistd.h>
E>int main(int argc,char* argv,char* env[]) { int i=0; for(; env[i];i++) {
E> printf("pid:%d,env[%d]:%s\n",getpid(),i,env[i]); } return 0;
}
就可以把我们的此程序的环境变量打印出来:
这个获取环境变量的方法和我们输入"env"命令获取的环境变量是一样的:

我们之前说过如果我们把PATH置空,很多系统命令都用不了了:
但是我们重启xshell之后就又可以用了。这是因为我们置空的是加载进内存的PATH。
我们重启之后系统解释器会重新读取环境变量表,形成新的环境变量,环境变量是脚本配置文件的形式存在的的。
在家目录下有个隐藏文件,bash_profile.
环境变量表就在这个文件里面。



假设我们自己写一个环境变量,
然后用env调用环境变量,通过管道只打印我们自己写的环境变量,显示找不到:

这是因为我们写的环境变量并没有被加载进环境变量表。
我们可以通过 "export"命令把我们写的环境变量加载进环境变量表里面,再通过env打印就可以打印出来了。

但是我们重启xshell之后我们配置的这个环境变量仍然会消失不见。只有当我们去家目录下面的bash_profile文件下写入我们的环境变量才能再次重启之后仍然会存在。
vim ~/.bash_profile
此刻我们就可以把我们自定义的变量打印出来看看:
假如我们不想给main函数传参呢?
有个外部变量叫 environ
它指向了char * env[ ]

我们把environ打印出来,main函数不带参照样可以把环境变量打印出来。
int main()
{ extern char** environ; int i=0; for(;environ[i];i++) { printf("%d,%s",i,environ[i]); } return 0;
}

到目前为止,我们获取环境变量的方法有:
main函数传参 getenv[ ] char** environ[ ]
环境变量具有全局属性
我们在我们将才的进程里再写个子进程,看它能获取我们子进程的环境变量吗
#include<stdio.h> #include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h> int main()
{ pid_t id=fork(); if(id==0) { extern char** environ; int i=0; for(;environ[i];i++) { printf("%d,%s",i,environ[i]); } } sleep(3); return 0;
}
照样可以,这也证明了环境变量具有全局属性。

我们自定一个本地变量
OUR_ENV=333
然后我们再把这个本地变量打印出来
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<unistd.h> int main() {
printf("OUR_ENV_ENV:%S\n",getenv("OUR_ENV"));return 0;
}
注意:因为是子进程,所以我们没export的时候子进程获取不到我们自定义的本地变量,会显示为null
当我们export把我们定义的环境变量载入bash之后,让它成为环境变量,环境变量具有全局性,子进程就可以获取到了:

内建命令
我们再写几个本地变量:
我们发现,a,b都为本地变量,echo是一个子进程,但是可以直接打印本地变量 a,b,这是为什么?
再比如,我们把PATH置空,这时候ls,touch这种命令都用不了了,但是echo还可以用
这是因为echo是shell的内置函数,这种命令叫做linux的内建命令。
内建命令不创建子进程。
和环境变量相关的命令

set:
把本地变量和环境变量全部打印出来:
set | grep+本地变量名功能:打印本地变量

c语言访问地址
程序的地址空间遵守的就是下面这张图:
我们把这各个区的存的值的地址打印出来看看:
int usa; int bbb=100; int main () { printf("公共代码区:%p\n",main); const char* str="helo djwd"; //常量区 printf("常量区:%p\n",str); printf("初始化全局数据区:%p\n",&bbb); W>printf("未初始化全局数据区:%p\n",usa); char* heap=(char*)malloc(100); printf("堆区:%p\n",heap); printf("栈区:%p\n",&str);

观察打印出来的地址可以发现一个问题,从公共代码区到常量区,再往下走,地址都是呈递增状态。
当到了堆区之后,从堆区到栈区,中间宽度变的特别大。
按照这个结果我们可以有这种推论:
得出结论:堆和栈相对而生。
验证
把堆区地址打印看一下:
char* heap1=(char*)malloc(100);
char* heap2=(char*)malloc(100);
char* heap3=(char*)malloc(100);
char* heap4=(char*)malloc(100); printf("堆区:%p\n",heap);
printf("堆区:%p\n",heap1);
printf("堆区:%p\n",heap2);
printf("堆区:%p\n",heap3);
printf("堆区:%p\n",heap4);
可以发现堆区越来越大,这也证明堆区向上增长
把栈区地址打印一下看一下:
char* str="hello";
char* heap1=(char*)malloc(100);
char* heap2=(char*)malloc(100);
char* heap3=(char*)malloc(100);
char* heap4=(char*)malloc(100); printf("栈区:%p\n",&str);
printf("栈区:%p\n",&heap);
printf("栈区:%p\n",&heap1);
printf("栈区:%p\n",&heap2);
printf("栈区:%p\n",&heap3);
printf("栈区:%p\n",&heap4);
观察图我们发现栈区越往下越小
如果定义一个结构体object ,里面有三个成员变量 int a,b,c,abc谁最大?
struct d
{ int a; int b; int c;
}object; printf("%p\n",&object.a);
printf("%p\n",&object.b);
printf("%p\n",&object.c);
很明显,c最大
这是因为虽然栈区向下增长,但整体是向上增长的:

假设我们定义一个 int b,一个int类型有4个字节,那就应该有4个地址,但是我们打印b的地址,显示出来只有一个,这个地址就是最小的地址。
然后向上按照int类型访问4个字节,访问到最大字节:
类型的本质叫做偏移量
c语言中就是以起始位置+偏移量访问任何地址。
定义一个int a,打印a的地址。
a因为是常量,所以在栈区,又因为后开辟,所有地址偏小。


现在我们a重定义为 static int a,此刻再重新打印a。我们发现a的地址变量,它和全局变量的地址是一个样子,也就是此时a就是一个全局变量:
所以我们可以说已初始化全局变量区就是静态区:
在栈区之上还有一个环境变量区和命令参数区:

重新理解地址
地址空间
写一个子进程,写一个父进程

pid_t id=fork();
相关文章:
Linux 环境变量 二
目录 获取环境变量的后两种方法 环境变量具有全局属性 内建命令 和环境变量相关的命令 c语言访问地址 重新理解地址 地址空间 获取环境变量的后两种方法 main函数的第三个参数 :char* env[ ] 也是一个指针数组,我们可以把它的内容打印出来看看。 …...
Beyond Compare4 30天试用到期的解决办法
相信很多小伙伴都有在使用Beyond Compare 4软件,如果我们没有激活该软件,就只有30天的评估使用期,那么过了这30天后我们怎么继续使用呢?下面小编就来为大家介绍方法。 打开Beyond Compare4,提示已经超出30天试用期限制…...
sentinel规则持久化-规则同步nacos-最标准配置
官方参考文档: 动态规则扩展 alibaba/Sentinel Wiki GitHub 需要修改的代码如下: 为了便于后续版本集成nacos,简单讲一下集成思路 1.更改pom 修改sentinel-datasource-nacos的范围 将 <dependency><groupId>com.alibaba.c…...
【Linux】tail命令使用
tail 命令可用于查看文件的内容,有一个常用的参数 -f 常用于查阅正在改变的日志文件。 语法 tail [参数] [文件] tail命令 -Linux手册页 著者 由保罗鲁宾、大卫麦肯齐、伊恩兰斯泰勒和吉姆梅耶林撰写。 命令选项及作用 执行令 tail --help 执行命令结果 参…...
【数据结构】面试OJ题——时间复杂度2
目录 一:移除元素 思路: 二:删除有序数组中的重复项 思路: 三:合并两个有序数组 思路1: 什么?你不知道qsort() 思路2: 一:移除元素 27. 移…...
LibreOffice编辑excel文档如何在单元格中输入手动换行符
用WPS编辑excel文档的时候,要在单元格中输入手动换行符,可以先按住Alt键,然后回车。 而用LibreOffice编辑excel文档,要在单元格中输入手动换行符,可以先按住Ctrl键,然后回车。例如:...
ideaSSM在线商务管理系统VS开发mysql数据库web结构java编程计算机网页源码maven项目
一、源码特点 SSM 在线商务管理系统是一套完善的信息管理系统,结合SSM框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发),系统具有完整的源代码 和数据库,系统主…...
数据结构 | 顺序表专题
数据结构 | 顺序表专题 文章目录 数据结构 | 顺序表专题课前准备1. 目标2. 需要的储备知识3. 数据结构相关概念 开始顺序表1、顺序表的概念及结构2、顺序表分类3、动态顺序表的实现初始化顺序表打印顺序表内存容量的检查顺序表的尾插顺序表的尾删顺序表的头插顺序表的头删在顺序…...
C++可视化 有穷自动机NFA 有穷自动机DFA
一、项目介绍 根据正则表达式,可视化显示NFA,DFA;词法分析程序 二、项目展示...
vite vue3 ts 使用sass 设置样式变量 和重置默认样式
1.安装scss 样式支持依赖 yarn add -D sass 2.使用sass <div><!-- 测试使用sass --><h1>测试使用sass</h1> </div><style scope lang"scss"> div {h1 {color: red;} } </style> 效果: 3.通过npm下载并复制…...
MySQL安全基线检查
目录 安全基线检查基础知识MySQL 的安全基线检查MySQL 更严格的一些基线检查内容一、安全基线检查基础知识 1、安全基线的定义: 安全基线是一个信息系统的最小安全保证,即该信息系统最基本需要满足的安全要求。它是在安全付出成本与所能够承受的安全风险之间进行平衡的合理…...
Unity主程如何做好游戏项目管理
前言 很多小伙伴最近在面试或者考虑跳槽,可能工作了3~5年了想涨薪或想做技术总监或主程, 可自己还是个雏,没有做过项目技术管理,怎么办?今天我给大家梳理一下作为一个技术总监或主程你应该如何带好一个游戏项目,做好技术管理。接…...
103.linux5.15.198 编译 firefly-rk3399(2)
1. 平台: rk3399 firefly 2g16g 2. 内核:linux5.15.136 (从内核镜像网站下载) 3. 交叉编译工具 gcc version 7.5.0 (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 4. 宿主机:ubuntu18.04 5. 需要的素材和资料ÿ…...
如何从Android手机上轻松恢复误删除的短信 ?
当您使用 Android 手机时,您可能会误删除一些 Android 短信。如果这些消息对您很重要,您可能想要恢复它们。在这种情况下,您可以尝试使用U1tData安卓数据恢复(奇客软件) 来完成这项工作。这篇文章将向您展示更多信息。…...
毅速丨金属3D打印能替代传统制造吗?
金属3D打印技术已经逐渐被很多行业认可和应用,但是目前,金属3D打印多数被作为传统制造技术的一种补充,暂时还不能完全替代传统制造。 金属3D打印使用的是金属粉末进行选择性激光烧结,打印时在成型缸里铺上金属粉末,打印…...
21个新的ChatGPT应用
自从GPT有了图识别功能后变的更加强大,特别是ChatGPT的视觉技术,为我们提供了无数的可能性。本文将深入探讨这21种应用场景,帮助理解其在日常生活和工作中的实际价值。 生活助手:为日常生活增添色彩 健身计划定制:你…...
【通信原理】第二章|确知信号
前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助。 高质量博客汇总 文章目录 前言 第二章 确知信号1. 确知…...
【JVM】类加载器
【JVM】类加载器 文章目录 【JVM】类加载器0. 类加载器概述1. 类加载器的分类1.1 启动类加载器1.2 Java中的默认类加载器1.2.1 扩展类加载器1.2.2 应用程序类加载器 2. 双亲委派机制2.1 类的双亲委派机制是什么?2.2 打破双亲委派机制2.2.1 自定义类加载器2.2.2 线程…...
利用Excel支持JUnit参数化测试
在JUnit里面,可以使用CsvFileSource读取csv文件进行参数化测试,可是CSV文件不支持格式,编辑颇为麻烦,尤其是多次编辑,因此自然想到是否可以使用Excel文件,可以有各种格式,支持各类数据。 最新开…...
第三章 SysML入门|系统建模语言SysML实用指南学习
仅供个人学习记录 UML与SysML的联系 可以稍微参考UML与SysML的联系 UML(统一建模语言)和SysML(系统建模语言)是两种与建模相关的语言,它们之间存在联系和区别。 SysML的图分类如下图所示。 SysML 图概述 这里只…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
