char* argv[]
argument vector(参数向量 / 数组)argv[0]:默认是程序本身的路径 / 名称;argv[1]:第 1 个用户传入的参数;argv[2]:第 2 个用户传入的参数;argc个元素。
在 C 语言的char* argv[]数组中(该数组也被称为 “命令行参数表”),无论参数数量是多少,argv的最后一个有效元素的下一个位置(即argv[argc])会被系统自动初始化为 NULL。
在执行命令
./test a b c时,这些参数会按顺序存入**char* argv[]**这个字符指针数组,具体对应关系是:
argv[0] 存储第一个参数:"./test"(程序本身的路径 / 名称)argv[1] 存储第二个参数:"a"argv[2] 存储第三个参数:"b"argv[3] 存储第四个参数:"c" (补充说明:终端中参数之间的空格是分隔符,所以./test a b c会被拆分成 4 个独立的字符串,依次填入argv数组的对应位置)
既然 main 函数可以接收 argc 和 argv 参数,这就直接证明 main 函数并非程序运行的 “原生起点”—— 程序启动时,操作系统先调用启动函数(如**Startup()**或**CRTStartup()**,不同编译环境命名略有差异),由这些启动函数完成程序运行前的基础初始化(比如内存分配、运行环境配置),最终再由启动函数主动调用 main 函数,并将命令行参数封装为 argc 和 argv 传递给它。
简言之:操作系统 → Startup/CRTStartup(启动函数) → main函数(接收参数执行),main 函数的参数正是这一调用链的直接体现。
核心是为指令、工具、软件等提供命令行选项的支持—— 通过在执行程序时传入不同参数,能让同一个程序实现不同功能。比如
ls -l(ls是程序,-l是命令行参数),传入-l就能让ls以详细列表形式显示文件,不传则是默认格式,灵活适配不同使用场景。


如果想实现多选项,可以用循环遍历所有参数 + 逐个匹配判断,示例代码:
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
// 1. 无参数时打印用法提示(argc=1 表示只有程序名)
if (argc == 1)
{
printf("Usage: %s -[a|b|c|d] [多个参数可叠加]\n", argv[0]);
printf("示例: %s -a -b -c\n", argv[0]);
return 1; // 退出程序,避免后续逻辑执行
}
// 2. 遍历所有传入的参数(i从1开始,跳过argv[0]程序名)
for (int i = 1; i < argc; i++)
{
// 逐个判断参数,匹配则执行对应功能
if (strcmp(argv[i], "-a") == 0)
{
printf("执行功能1(参数-a)\n");
}
else if (strcmp(argv[i], "-b") == 0)
{
printf("执行功能2(参数-b)\n");
}
else if (strcmp(argv[i], "-c") == 0)
{
printf("执行功能3(参数-c)\n");
}
else if (strcmp(argv[i], "-d") == 0)
{
printf("执行功能4(参数-d)\n");
}
else
{
// 3. 识别到非法参数时提示,并继续处理其他参数
printf("警告:无效参数 %s,仅支持 -a/-b/-c/-d\n", argv[i]);
}
}
return 0;
}实际上,我们也可以通过main函数的环境变量参数(如char *envp[]),获取当前程序所在 bash 进程的所有环境变量。

envp和argv是同类型的字符指针数组(都属于 “参数向量表”),envp对应的是环境变量表;由于环境变量的数量不固定,所以需要通过envp末尾的NULL指针来判断遍历的结束。

前面已经讲了 3 种获取环境变量的方式:
echo命令(如echo $PATH),直接打印单个环境变量的值;env命令,查看所有环境变量的列表;main函数的环境变量参数(如char *envp[]),在代码中获取环境变量。接下来我再讲解一种通过C语言接口获取环境变量的方法。



基本语法:
export 环境变量名=值示例:

说明:
export的作用是将变量标记为 “环境变量”,使子进程可以继承该变量;需将设置指令写入 Shell 配置文件(以 Bash 为例):
编辑配置文件:
echo 'export 环境变量名=值' >> ~/.bashrc示例:
echo 'export MYENV="hello world"' >> ~/.bashrc✅ 当前终端进程想用新配置 → 必须执行 source ~/.bashrc(相当于 “给当前 Shell‘刷新内存’”);
✅ 不想执行 source → 直接关闭当前终端,重新打开新终端即可(新终端启动时会自动读取修改后的~/.bashrc)。
说明:
~/.zshrc);核心命令:unset
# 取消单个环境变量(比如你设置的MYENV)
unset MYENV
# 验证是否取消:输出为空则成功
echo $MYENV补充:清空 PATH(慎用!)
如果想临时清空某个环境变量的值(而非彻底取消),可以直接赋值为空:
# 仅清空值,变量仍存在(不推荐,容易踩坑)
MYENV=""
# 验证:输出为空,但变量还在
env | grep MYENV # 仍能看到MYENV=针对你之前写到~/.bashrc里的export MYENV="hello world",操作步骤:
编辑配置文件,删除环境变量定义:
# 用vim打开~/.bashrc
vim ~/.bashrc
# 操作步骤:
# 1. 按G跳到文件最后一行
# 2. 找到你添加的export MYENV="hello world"这一行
# 3. 按dd删除该行(或在行首加#注释掉)
# 4. 按ESC → 输入:wq 保存退出让修改生效:
# 刷新当前终端的配置(立即永久取消,不想用该指令重新打开终端也会生效)
source ~/.bashrc
# 验证:无论当前终端/新终端,echo $MYENV 都为空
echo $MYENV # 输出空父进程(Shell)通过export MYENV=123456设置环境变量后,子进程(./test程序)能通过getenv继承并读取该值(运行./test输出 “获取到的 MYENV 值:123456”);
环境变量的 “全局” 是父→子进程链条内的单向共享:子进程会继承父进程的环境变量,但子进程修改的是独立副本,不影响父进程。
子进程会继承父进程的环境变量:


子进程对环境变量的修改不影响父进程:


这是因为进程的环境变量是 “复制继承” 而非 “共享”,底层逻辑是:当父进程创建子进程时,会把自己的环境变量完整复制一份给子进程 —— 子进程拿到的是 “副本”,不是和父进程共享同一份数据。所以:
本地变量是仅在当前 Bash 进程内生效的变量(不加export的变量),不会被 Bash 的子进程继承。
证明本地变量不会被继承:


之前我们认为 “所有命令都会以 Bash 进程的子进程形式执行”,这个说法其实不准确。实际使用中,Shell 命令可以分为两类:常规命令和内建命令。
1. 常规命令 常规命令的执行,是通过创建子进程来完成的—— 这些命令是独立的程序,Bash 会启动一个新的子进程,让子进程去运行这个程序,程序跑完子进程就结束。 2. 内建命令 内建命令的执行,Bash 不会创建子进程,而是由 Bash 自己直接执行 —— 相当于 Bash 调用了自己内置的功能(类似 Bash 自己写好的函数),不用额外开新进程。


执行./test(常规命令)时,Bash 会创建子进程,但父进程的本地变量不会传给子进程,所以./test读不到MYENV;
而echo是内建命令,执行时 Bash 不会开子进程,直接在自身进程内运行,因此能访问到父进程的本地变量,所以echo $MYENV能输出123。
cd内建指令】在 Shell 中,cd是内建指令,它的底层是通过chdir系统调用函数实现的。
chdir**函数**
int chdir(const char *path);path**:字符串形式的目标路径(支持绝对路径 / 相对路径)。0;-1,同时会设置errno标识错误原因#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[], char *envp[])
{
sleep(20); // 延迟,方便观察进程状态
printf("change begin\n");
if (argc == 2) // 接收命令行参数作为目标路径
{
chdir(argv[1]); // 调用chdir修改当前进程的工作目录
}
sleep(20);
return 0;
}
第一次(change begin前):指向的是原目录/home/lih/code-under-linux/Test-course;
第二次(change begin后):指向的是目标目录/home/lih—— 说明chdir确实成功修改了子进程的工作目录!
ls -ld /proc/[进程ID]/cwd作用:查看cwd(进程工作目录的软链接)自身信息
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=4u7xbz032vy