【问题标题】:C segmentation fault when passing a NULL pointer despite a conditional telling the function not to run if a NULL parameter is passed?尽管有条件告诉函数在传递 NULL 参数时不要运行,但在传递 NULL 指针时出现 C 分段错误?
【发布时间】:2015-09-08 03:52:46
【问题描述】:

我有一个处理字符串数组的程序。其中一种方法从所述数组中的指定位置删除字符串。代码如下:

void RemoveStringAt(char *array[], int pos)
{
    if((array[pos]!=NULL)&&(array!=NULL)&&(pos!=NULL))
    {
        free(array[pos]);
        array[pos]=NULL;
    }
}

该项目的一个规范是它在传递 NULL 值时不应导致段错误。这是我尝试时发生的情况:

 RemoveStringAt(NULL, NULL);

还有输出:

Segmentation fault (core dumped)

如果执行该方法的核心部分的条件之一是传递的值都不能为 NULL,为什么我会遇到分段错误?

【问题讨论】:

  • 您的支票顺序错误。 array[pos] 在检查 array != NULL 之前导致 seg 错误。
  • pos != NULL 是语义错误; pos 是一个整数。如果你的意思是pos != 0,那就写吧
  • 你害怕空格吗? if (array && pos != 0 && array[pos]) 更清晰。无需将指针与 NULL 进行比较
  • 这个测试NULL != array[pos] 是多余的,因为free() 接受NULL
  • 另外int 最好是size_t,这是索引数组的首选类型。这里也不需要负值。

标签: c string segmentation-fault


【解决方案1】:

因为您在检查过程中取消引用 NULL 指针:

if((array[pos]!=NULL)...

array 是 NULL,所以你不能做array[pos]。在 C 中,if 条件从左到右计算,所以只需将条件更改为如下所示。也就是说,如果array 为NULL,则更改顺序以便永远不会评估array[pos]

if((array!=NULL) && (pos < MAX_POS) && (array[pos]!=NULL))

请注意,您的原始支票 pos!=NULL 不正确。出于几个原因。 1. pos 不是指针,因此将其与 NULL 进行比较在语义上是不正确的。 2.NULL 通常定义为00 是一个有效的pos 值。因此,您需要定义一个 MAX_POS 指定 array 中的条目数,或者更好的是,将其作为显式参数传递给函数。

最后,毕竟,如果你不想,你甚至不必让array[pos]!=NULL 签入条件。 if 块内的任何内容都不会导致 segv,即使 array[pos]NULL,因为 free 被定义为接受 NULL 参数。

【讨论】:

    【解决方案2】:

    问题出在

    if((array[pos]!=NULL)&&(array!=NULL)&&(pos!=NULL))
    

    第一个

    if((array[pos]!=NULL)
    

    将被检查,如果数组是NULL,它将给出分段错误。在这种情况下

    (array!=NULL)&&(pos!=NULL))
    

    将被检查。

    你的代码应该是这样的

    void RemoveStringAt(char *array[], int pos)
    {
        if((array!=NULL)&& (array[pos]!=NULL))
        {
            free(array[pos]);
            array[pos]=NULL;
        }
    }
    

    并且不应该有NULL 检查pos,因为NULL 被定义为0 并且0 是数组中的有效索引,所以我们应该能够在0 索引处释放。

    【讨论】:

    • pos!=NULL 没有意义。
    • @ask 是的,我在最后一行写了些什么。数组中的索引可以接受 0。
    • 那么你为什么不把它从你的示例代码中删除,因为“代码应该[不]像[this]”。
    【解决方案3】:

    输入验证的最佳解决方案如下所示:

    void RemoveStringAt(char *array[], int pos)
    {
      if (NULL != array) && (0 <= pos))
      {
        free(array[pos]);
        array[pos]=NULL;
      }
    }
    

    如果pos 越界访问array,显示的验证仍可能无法阻止调用失败。这对于给定的最小接口是不可能的。

    【讨论】:

    • (NULL != array)pos 而不是 (array != NULL) 的做法非常有趣。可能是我第一次看到。
    • @RastaJedi:这使用“Yoda-Conditions”(en.wikipedia.org/wiki/Yoda_conditions)调用。
    猜你喜欢
    • 2011-12-23
    • 2014-04-26
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    • 1970-01-01
    相关资源
    最近更新 更多