【问题标题】:C segmentation fault after altering argv更改 argv 后的 C 分段错误
【发布时间】:2015-12-17 14:49:06
【问题描述】:

我想在 C 中更改 argv 的值,但我遇到了分段错误。这是代码。

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    for (int i = 1; argv[i]; i++)
    {
        char *val;

        printf("before: %d %s\n", i, argv[i]);
        argv[i] = "bar=foo";
        printf("after: %d %s\n", i, argv[i]);

        char *arg = argv[i];
        val = strchr(arg, '=');
        *val = '\0';
    }
    return 0;
}

我正在传递参数 foo=bar(并尝试将第 11 行中的参数更改为 bar=foo)。输出如下所示:

before: 1 foo=bar
after: 1 bar=foo

所以,修改确实发生了,但是*val = '\0'; 行导致了分段错误。

谁能告诉我为什么会这样以及如何预防?

【问题讨论】:

  • 如果您只传递 1 个参数,则 argv[i] 仅在 i 取值为 0 时才有效。在您的 for 循环中,您正在检查 argv[1] 作为要查看的谓词的第一次迭代如果你应该继续循环,但这不起作用。
  • @IIIIIIIIIIIIIIIIIIIIIIIIargv[0]始终是程序的名称,如果你传递一个arg,argv[1]是有效的,argv[2]应该是NULL
  • @Holt argv[0] 可以是 NULL。 C11 §5.1.2.2.1 2
  • @Holt: 1) NULL 是一个带有空指针常量的宏。指针不能是宏。它可以是一个空指针,但是,它等于一个空指针常量。 2) 请指出标准规定argv[2] 必须是空指针的位置。
  • @Holt:我的立场是正确的。重读标准中的行。 (顺便说一句:我要求提供指向标准的指针,即权威参考)。仅供参考:port70.net/~nsz/c/c11/n1570.html#5.1.2.2.1p2 第二项。

标签: c segmentation-fault argv


【解决方案1】:

您让argv[i] 指向一个字符串文字,它是一个只读 字符数组。然后你尝试修改这个只读数组导致未定义的行为

您应该将const char * 用于字符串文字是有原因的。


有几种方法可以解决您的问题。第一个也是最简单的,特别是如果您要对所有参数使用相同的字符串(除了在您展示的人为示例中不太可能)是使用数组,例如char argument[] = "bar=foo";。依靠数组自然衰减到指向它们的第一个参数的指针,您可以在分配给argv[i] 时使用它,并将数组修改为您心中的内容。

但就像我说的那样,除了简单的示例之外,这并不是很有用。这给我们留下了另一种选择,例如使用strdup 动态分配和复制字符串(或者如果strdup 不可用,它不是标准功能,您可以手动使用mallocstrcpy)。由于您随后已动态分配内存,因此也可以根据您的内心内容对其进行修改。这里的问题是您需要跟踪原始指针并使用free 再次释放它们。

所以这些基本上是您可以使用的两种解决方案。一种是不切实际的,另一种具有动态内存分配和所有相关问题。对于您的问题,确实没有好的解决方案,尤其是没有简单解决方案。

【讨论】:

  • 我明白你的意思,但我不确定如何使用const char*然后修改argv[i]
  • @drZaius 你不能,主要是在处理字符串文字时,你真的需要考虑它们的只读方面。但是,我确实编辑了答案以包含几个可能的解决方案。
  • 没错,我实际上是在修改一个可用于每台 Unix 机器的工具(但应保持无名)。就在您进一步解释之前,我尝试使用数组,它确实完成了工作!所以没有段错误了,我的修改已经启动并运行了。
【解决方案2】:

你在这里写一个字符串文字

val = strchr(arg, '=');
*val = '\0';

字符串文字存在于程序的只读段中,尝试更改它们会调用未定义的行为。

这一行之后

argv[i] = "bar=foo";

argv[i] 指向一个字符串文字 "bar=foo" 然后,创建一个指向 argv[i] 的新指针 arg,最后是 val 指向 arg 中的 = 的指针,然后你就去并尝试用nul 覆盖。

【讨论】:

    猜你喜欢
    • 2020-09-18
    • 1970-01-01
    • 1970-01-01
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    • 1970-01-01
    相关资源
    最近更新 更多