argv 的重新分配

Reallocation of argv

我正在查看 GNU coreutils 包的代码,特别是 the program 'yes',当我在 main 函数(第 78 行)中看到这段代码时:

if (argc <= optind)
{
  optind = argc;
  argv[argc++] = bad_cast ("y");
}

数组argv如何展开成这样?显然,只是将任何代码片段从上下文中取出是一个非常糟糕的主意,所以我事先查看了 argv 是否被修改了,除了在对 [=15= 的调用中似乎没有被修改过],它似乎不需要 "new size" 或类似的参数(但在 C 中,就像任何语言一样,事情并不总是它们看起来的那样)。

我决定编写一个简单的程序来测试我是否可以在 argv

上调用 realloc()
char** new_argv = realloc(argv, ++argc * sizeof*argv);

它有效(在 Windows 10 上使用 VS2013)。它返回一个指向已分配内存的指针。当然,如果它是未定义的行为,那实际上并不意味着 任何东西

那么,长话短说,我的问题是,argv 是如何分配的?重新分配 argv 真的安全吗?

首先,argv[argc]定义为NULL

其次,argc++ 递增 argc 但 returns 它的旧值。

因此,argv[argc++] = ... 不会调用未定义的行为;它只是将一个新值分配给先前的 NULL 指针。

argv[argc++] = bad_cast ("y");

这不会扩展 argv 数组。它只是给 argv[argc] 赋值,然后递增 argc。这确实打破了 argv[argc] == NULL 的初始保证,但只要代码不依赖于它是有效的。

标准保证:

The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.

它没有明确保证 argv 指向的数组中的 char* 指针是可修改的,但这是一个合理的假设。 (严格来说argv指向数组的第一个元素,而不是数组本身,但是那句话已经够长了。)

char** new_argv = realloc(argv, ++argc * sizeof*argv);

这有未定义的行为。 realloc 的第一个参数必须是空指针或指向由 malloccallocrealloc 或等效项分配的内存的指针。 argv 指向的内存在输入 main 之前以某种未指定的方式分配。您可以复制数组,但不能合法地释放它,这是 realloc 所做的一部分。如果 realloc 调用对你来说表现得 "correctly",那你就太不走运了。 (如果你幸运,你的程序就会崩溃,这会告诉你有问题。)