检查 (*argv == NULL) 的原因是什么?

11

我正在学习数据结构课程,在这门课中,我们的任务是用C++编写一个网络爬虫。为了给我们一个启动,教授提供了一个程序来获取给定URL的源代码和一个简单的HTML解析器来去除标签。该程序的主要函数接受参数,因此使用argc/argv。用于检查参数的代码如下:

// Process the arguments
if (!strcmp(option, "-h"))
{
    // do stuff...
}
else if (!strcmp(option, ""))
{
    // do stuff...
}
else if (!strcmp(option, "-t"))
{
    // do stuff...
}
else if (!strcmp(option, "-a"))
{
    // do stuff...
}

if ( *argv == NULL )
{
    exit(1);
}

“option”已被填入argv [1]中的开关,而argv [2]及更高版本具有其余参数。我很好理解第一个块,如果开关等于字符串,则根据开关执行相应操作。但我想知道最后一个if块的目的是什么。

也许我的C ++有点生疏,但我记得* argv相当于argv [0],基本上意味着它正在检查是否存在参数。除了我印象中argv [0]始终(至少在大多数实现中)包含正在运行的程序的名称。 我想到了如果argc等于0,argv [0]可能为null,但是在Google上搜索时,我找不到一篇文章确定这是否可能。

所以我转向您。 最后一个if块到底检查了什么?

编辑:我采用了所选答案评论中提供的推理,认为可能会故意导致argv [0]变为NULL,或者基于main的特定平台实现而变为NULL。


3
注意,argv不是数组而是指针。这意味着您完全可以使用 argv++ 来遍历选项。您不必修改 *argv 的值。 - Johannes Schaub - litb
出于好奇,当你问教授时,他/她给出了什么原因? - Daniel
现在,5年后,我真的不记得了。我似乎依稀记得曾经问过我的TA,并且答案和已接受的答案评论中的推理相同(请参见问题中的编辑),但我可能是在编造事实,记错了。 :P - Shaun Hamman
我知道这已经很晚了,但是作为一条注释,你可以轻松地使用getopt()解析命令行选项。 - RastaJedi
不确定将此标记为重复是否有必要,因为这个问题是在链接的“重复”之前3个月被提出并回答的。(事实上,这已经是7年前的事情了 >_>) - Shaun Hamman
4个回答

13

3.6.1/2:

如果argc不为零,则这些参数应在argv[0]中提供,虽然...而且argv [0]必须是指向表示用于调用程序的名称的NTMBS的初始字符的指针或“”。 argc的值应该是非负的。 argv [argc]的值应该是0。

强调是我的。argc仅保证为非负数,不一定是非零数。

这是进入main函数时的情况。也有可能“//do stuff”修改了argv的值,或者它指向的数组的内容。在选项处理代码处理它们时,从argv中移除或跳过值不是完全没有先例的。因此,对于*argv == null的测试可能正在测试是否还剩下任何命令行参数,在选项已被删除或跳过后。您需要查看其余代码以确定。


10

argc会提供传递的命令行参数数量。你不需要检查argv的内容来查看是否有足够的参数。

if (argc <= 1) { // The first arg will be the executable name
   // print usage
}

3
@Shaun:是的,*argvargv[0] 是相同的。当你从普通 shell 运行应用程序时,通常不可能这样做。但我认为,如果您使用 exec 系统调用并手动传递数组来直接从另一个程序执行进程,则可能实现这一点。 - Mehrdad Afshari
1
@Shaun:程序名称出现在argv中并不是魔法。当shell生成进程时,它会将该名称放入数组中。在某些平台上,可能手动制作一个启动器进程,不向您的程序传递此类参数。 - Mehrdad Afshari
2
@Shaun:也许你的教授是错的? - kennytm
2
@Shaun,程序可能已经对“argv”进行了递增,因此现在指向了空指针。请参见@Steve的答案。 - Johannes Schaub - litb
1
@Shaun:在正常情况下可以这样假设。但是由于argc是专门提供来计算参数数量的,为什么要冒险不这样做呢?添加一个检查argcif语句并不是什么大问题。 - Mehrdad Afshari
显示剩余5条评论

4
记住C语言的可移植性,它可能不总是在像Windows或Unix这样的标准平台上运行。也许它是在你的洗衣机里运行的某些微代码,在某些便宜的、被黑客入侵的环境中运行。因此,在解引用指针之前,确保指针不为空是一个好习惯,这可能导致了这个问题。
即使如此,你是正确的。* argv与argv [0]相同,并且如果提供了环境,argv应该由环境初始化。

5
也许是你的洗衣机里面的一些微代码。太好了,现在我等着看到“抱歉,您必须更新‘Adobe Flash’至最新版本才能进入漂洗程序”的提示信息。 - Tom West
@TomWest 现代化的说法是:“此插头已不再支持使用。请前往最近的维修店更新。” - undefined

4

只是一种猜测。

如果您的教授指的是这个,那会怎样呢?

while(*++argv !=NULL)

    printf("%s\n",*argv);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接