我正在使用此代码...
#include <stdio.h>
int main(int argc,char *argv[]){
int i =0;
if (argc == 1){
printf("You have entered 1 argument and you suck \n");
}
else if (argc > 1 && argc<4){
for (i=0;i<4;i++){
printf("you have entered the following args %d.%s \n",(i),argv[i]);
}
printf("\n");
}
else{
printf("You have entered more than four arguments and you suck.\n");
}
return 0;
}
如果我将for循环从for (i=0;i<4;i++)
更改为for (i=0;i<7;i++)
,我会得到此输出:
cam@cam:~/Desktop/D/c/c-code$ ./ex12 hi there
you have entered the following args 0../ex12
you have entered the following args 1.hi
you have entered the following args 2.there
you have entered the following args 3.(null)
you have entered the following args 4.XDG_VTNR=7
you have entered the following args 5.LC_PAPER=en_IN.UTF-8
you have entered the following args 6.ORBIT_SOCKETDIR=/tmp/orbit-cam
为什么没有错误?为什么生成与我的操作系统相关的变量?
答案 0 :(得分:5)
访问数组超出范围会导致未定义的行为。未定义行为的后果是未定义。纯粹巧合的是,你碰巧正在阅读一些环境变量。在其他系统上,或者在这种行为的其他示例中,您最终可能会巧合地阅读其他一些信息(请参阅 heartbleed 以获取一个值得注意的示例)或巧合地导致段错误(崩溃)......然而,所有这些结果纯属巧合,并且不能依赖。
答案 1 :(得分:3)
没有额外的参数&#34;生成&#34;。相反,由于C没有边界检查(与其他语言不同),因此您访问了数组边界之外的内存,这恰好是环境变量。
答案 2 :(得分:3)
Unix系统上程序的正常内存布局是指向程序参数的指针数组后面紧跟着指向环境变量的指针数组。
你正在做的是超越参数指针数组(注意在argv[argc]
处有一个空指针)和环境指针数组,它也由空指针终止。
因为您正在超越argv
数组的末尾,所以您正在调用未定义的行为。这很危险:任何事情都可能发生。但有时,结果是良性的 - 但是 ,你永远不能依赖它。
有义务免责声明, 您可以使用以下代码完整转储您的环境。但是,您 必须 才能理解C标准在明确标记的行之后不保证任何行为(POSIX也没有)。
envp
的额外main()
参数在C标准的附件J.5.1中作为公共扩展名注明 - 由Microsoft Windows和Unix系统支持。
J.5.1环境参数
在托管环境中,
main
函数接收第三个参数char *envp[]
, 指向以char
为指针的以null结尾的指针数组,每个指针都指向一个字符串 它提供有关此程序执行环境的信息 (5.1.2.2.1)。
这不是标准规定的;它被标准认可为通常可用的。在POSIX系统上,您还可以通过全局变量char **environ
获取环境变量。而且,如果您使用setenv()
或putenv()
来操纵环境,则无法保证environ
中存储的值与envp
中存储的值保持一致{ {1}}。
main()
请注意,即使Windows支持#include <assert.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp)
{
int i;
printf("Argc: %d\n", argc);
for (i = 0; i < argc; i++)
printf("Arg[%d]: <<%s>>\n", i, argv[i]);
assert(argv[argc] == 0);
assert(argv[i] == 0);
/* Print the environment cleanly on most systems */
char **ep;
for (ep = envp; *ep != 0; ep++)
printf("Env[%d]: <<%s>>\n", (int)(ep - envp), *ep);
printf("Number of environment variables: %d\n", (int)(ep -envp));
/* From here on, neither the C standard nor POSIX guarantees anything */
/* In practice, it works on Unix systems; I don't know about Windows */
assert(&argv[argc+1] == envp);
for (i++; argv[i] != 0; i++)
printf("Env[%d]: <<%s>>\n", i - argc - 1, argv[i]);
printf("Number of environment variables: %d\n", i - argc - 1);
return 0;
}
的第三个参数,也不能保证它所指向的内存紧跟在main()
所指向的内存之后(尽管它不会令人惊讶地发现它与Unix上的布局相同)。从技术上讲,Unix上并不保证argv
数组紧跟在envp
数组之后;但是,我从来没有遇到过这样的系统。
argv
程序允许您为其运行的命令设置环境,env
选项忽略任何继承的环境。这允许我运行上面的代码(编译成程序-i
),如下所示:
ev2