1. 命令行参数
在有的地方会看到main
函数的参数有下面这种写法:
C
#include <stdio.h>
// agrc表示的是argv[]的元素个数,argv[]是指向一个一个字符串的指针数组(以NULL结尾)
int main(int argc, char* argv[])
{
printf("hello world!\n");
return 0;
}
那么argv[]
到底指向谁呢?直接用代码来看一下:
C
#include <stdio.h>
int main(int argc, char* argv[])
{
for (int i = 0; i < argc; i++)
{
printf("argv[%d]: %s\n", i, argv[i]);
}
return 0;
}
运行后的效果:

这里打印了argv[0]:./a.out
,那么再加上一个-a、-b、-c呢?

显而易见,在命令行输入的命令都变成字符串,存在了argv[]
这个指针数组里,并且argv[0]
永远是指向我们的可执行程序的名字。那么为什么这么做呢? 下面再来看一段代码:
C
#include <stdio.h>
// 这段代码的主要功能是检查命令行参数的数量。如果参数数量不等于2,则输出使用说明并返回1。
int main(int argc, char* argv[])
{
if (argc != 2)
{
printf("Usage: %s -v1/-v2/-v3\n", argv[0]);
return 1;
}
return 0;
}
运行后就可以看到出现了提示:

把代码稍作修改一下:
C
#include <stdio.h>
#include <string.h>
// 这段代码首先检查命令行参数的数量是否为2,如果不是则输出使用说明并返回1。
//然后根据第二个参数(功能选项)执行相应的功能。如果输入的功能选项不支持,则输出"功能不支持"。
int main(int argc, char* argv[])
{
// 检查参数数量是否正确
if (argc != 2)
{
printf("Usage: %s -v1/-v2/-v3\n", argv[0]);
return 1;
}
// 根据参数执行相应的功能
if (strcmp(argv[1], "-v1") == 0)
{
printf("这是功能1\n");
}
else if (strcmp(argv[1], "-v2") == 0)
{
printf("这是功能2\n");
}
else if (strcmp(argv[1], "-v3") == 0)
{
printf("这是功能3\n");
}
else
{
printf("功能不支持\n");
}
return 0;
}
这时再运行:

这时就可以解答上面的问题了:为什么这么做? 在使用Linux 系统的时候,例如ls
命令,后面可以跟着不同的选项,比如:ls -l -a
,而命令的本质是C或者C++程序 ,选项本质上就是字符串 ,这就让选项可以使用一定的方式传递给程序内部的main函数,在程序实现的时候就能根据不同的选项,实现不同的功能。
那么这些命令行参数首先会被谁拿到呢?是被Bash
拿到了,前面文章有提到过,我们所运行的程序的父进程都是Bash
,并且调用fork
函数后,只要父进程不做修改,父进程和子进程的代码和数据是共享的,所以子进程就可以拿到命令行参数。
具体是怎么做的后面文章再解释。
这时可以输出几个结论:
- 一个程序在运行的时候,
argc
最小为1,argv[]
最少有一个元素(程序名)。 - 有几个子串(空格隔开),
argc
就是几。
2. 环境变量
环境变量是系统级别的全局变量,不同的变量具备不同的用途。
3. Linux环境变量
使用env
命令可以查看当前系统的所有环境变量,下面是几个主要的环境变量解释:
- SHELL:当前用户使用的登录shell。
- HISTSIZE:命令历史记录的大小,下图是1000,表示最多保存1000条命令历史。
- LANGUAGE:系统语言环境。
- HISTTIMEFORMAT :命令历史记录的时间格式,这里是
%F %T
,表示记录日期和时间。 - PWD:当前工作目录的路径。
- LOGNAME:当前登录用户的用户名。
- HOME:用户的主目录路径,也就是家目录。
- USER:当前登录用户的用户名。
- PATH:可执行文件的搜索路径。
- OLDPWD:上一个工作目录的路径。
环境变量提供了关于当前用户会话、系统配置和环境设置的信息。

3.1 PATH
为什么在执行ls
等命令的时候,不需要指定路径,而运行我们自己写的程序就需要指定路径,否则就会报错呢?是因为OS要找我们的执行程序,那他到哪里去找呢?是去/usr/bin
这个路径下去找,因为PATH
包含了这个路径。所以操作系统查找可执行命令,是在环境变量PATH
中查找的。Windows配置环境变量也是这个目的,可以让程序直接使用命令行的方式运行,不需要带指定的路径。


使用echo $PATH
命令来查看。在运行命令的时候,系统会在PATH
中的多个路径寻找(不同路径使用 " : " 隔开)。

修改PATH:
- 使用
PATH=''
即会删除所有环境变量。export PATH=$PATH:要添加的路径
即可添加新的环境变量。
4. 如何获取环境变量
4.1 main函数获取
在上面展示了main
函数可以有两个参数,但实际上还可以有第三个参数:
C
// 这里的env也是一个指针数组(以NULL结尾),指向了一个个字符串,也就是环境变量的K==V的字符串。
int main(int argc, char* argv[], char* env[]) {}
接下来使用main
函数获取一下环境变量:
C
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[], char* env[])
{
// 打印环境变量
for(int i = 0; env[i]; i++)
{
printf("env[%d]:%s\n", i, env[i]);
}
return 0;
}

4.2 getenv函数获取
还有另一种获取环境变量的方法:getenv
函数。
- 功能:获取环境变量的值。
- 用法:
char *getenv(const char *name);
- 参数:
name
是环境变量的名称。 - 返回值:如果找到指定的环境变量,则返回该变量的值;否则返回
NULL
。

C
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char* path = getenv("PATH");
printf("PATH = %s\n", path);
return 0;
}

4.3 environ全局指针获取

C
#include <stdio.h>
#include <stdlib.h>
int main()
{
extern char** environ;
for(int i = 0; environ[i]; i++)
{
printf("environ[%d]: %s\n", i, environ[i]);
}
return 0;
}

5. 为什么要有环境变量
下面这段代码通过getenv
函数获取环境变量USER
,对比是否是指定用户运行程序。
C
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* who = getenv("USER");
if(strcmp(who, "djn"))
{
printf("非指定用户,无法执行!\n");
return 1;
}
printf("用户正确,程序已执行!\n");
return 0;
}
用户名正确:

即使是root用户也无法运行:

那么如果想写一个获取当前路径的代码,只需要获取环境变量中的PWD
即可:
C
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* pwd = getenv("PWD");
printf("%s\n, pwd");
return 0;
}
通过上面例子就可以了解:为什么要有环境变量?因为不同的环境变量有不同的用途。