【问题标题】:Check if a pointer points inside an array in standard C/C++ [duplicate]检查标准C / C ++中的指针是否指向数组内[重复]
【发布时间】:2012-06-22 22:17:12
【问题描述】:

可能重复:
checking if pointer points within an array

如果我有一个数组和一个大小,并且我想检查给定的指针是否指向数组中的一个元素,那么在标准 C 或 C++ 中是否有任何方法可以在不调用 UB 的情况下这样做?

这行得通吗?

bool is_inside(someType * array, int size, someType * other_pointer){
    for (int i = 0; i < size; i++)
        if (array + i == other_pointer)
            return true;
    return false;
}

编辑:据我了解,除了==!= 之外,您不能对未指向没有UB 的同一数组的指针使用比较(尽管实际上它按预期工作)。我错了吗?

【问题讨论】:

  • 那你测试了吗?有用吗?
  • @Astor 测试不是确保它“不调用 UB”工作的好方法。
  • @R.MartinhoFernandes——虽然它实际上可能并不指向数组中的元素。
  • @R.MartinhoFernandes 当你这样说我想你是对的。
  • @R.马蒂尼奥费尔南德斯呢:type T a[5];type T b;is_inside(a, 5, &amp;b);

标签: c++ c pointers


【解决方案1】:

这取决于你所说的 UB 是什么意思。

具体来说,对于指针比较,C++ 标准的第 5.9 节“关系运算符”说:

如果两个相同类型的指针 p 和 q 指向不同的对象 不是同一对象的成员或不同功能的成员,或者如果只是其中之一 它们为空,p&lt;qp&gt;qp&lt;=qp&gt;=q 的结果未指定。

请注意,行为是未指定(意味着比较的结果可能是truefalse - 换句话说,结果并没有告诉你任何有用的信息 - 但实现不需要指定哪个)而不是 undefined(意味着编译器或生成的程序可以做任何事情)。

但是,到目前为止,我只看到一个实现系列没有使用 Kirill 之类的代码完成预期的事情:

bool inside = (other_pointer >= array) && (other_pointer < array+size);

这些实现是用于构建 MS-DOS 实模式程序的编译器,其中地址具有段落和偏移部分。地址 FF00:0010 和 FF01:0000 指向相同的内存位置,但如果我没记错的话,编译器不能保证以预期的方式运行,除非为某些内存模型编译(当然是 HUGE 模型,但也可能是其他模型)。

但是,如果 pq 没有指向现有对象(例如,指针已被释放),那么无论您做什么,行为都将是未定义的。所以你不能用这种方法来判断一个指针是否仍然有效。

【讨论】:

  • FF00:0000 转换为 FF00*10+0000=FF000,而如果 FF001:0010 是像 FF01:0010 这样的正确指针,则 FF001:0010 会转换为 FF01*10+0010=FF020。检查数学。
  • 啊我错了。它只是未指定。谢谢。
  • 感谢 Alex 的更正。
【解决方案2】:

数组保证在内存中是连续的,所以只需检查指针是否在第一个元素和最后一个元素的地址范围内。

【讨论】:

  • 还要检查指针和数组地址的差是sizeof(someType)的倍数。
  • @Alex:实际上,我不同意。正如 R. Martinho Fernandes 所说,无论如何这都是一个无效的指针。
  • 您不希望函数为无效指针返回 true。
  • @Alex:我认为返回 false 再好不过了。为什么你首先有一个无效的指针?我会说未定义的行为,我什至不会具体说明会发生什么。您知道哪些函数会在传递无效指针时指定它们的行为?
  • 在 C 和 C++ 的大多数实际实现中,神奇的 UB 并不是那么神奇,指针只是 CPU 用作地址的数字。如果你正在编写内核系统调用函数之类的东西,你真的很想检查这样的东西,不管语言标准是否告诉你它已经是 UB 或者将会有 UB。
【解决方案3】:

你可以简单地写:

bool inside = (other_pointer >= array) && (other_pointer < array+size);

这是合法检查。

【讨论】:

  • 还要检查指针和数组地址的差是sizeof(someType)的倍数。
  • 另外,注意加减法溢出。
  • @Alex "如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则计算不会产生溢出;否则,行为未定义。”从§5.7/6.
  • 假设给出的尺寸不正确,那么该函数的唯一合理实现是std::terminate()。你无能为力。
  • @JonathanWakely:我相信std::less for pointers 只保证适合在集合等中使用的顺序。不保证适合确定和 object 是否是一个元素的一个数组。数组可能会出现交错。
【解决方案4】:

您的解决方案可以工作,但不是最佳的,因为它包含一个不必要的循环。

你应该做的是获取一个指向数组的指针,数组大小以字节为单位,并检查指向的地址是否在该数组占用的地址空间内。

【讨论】:

  • 还要检查指针和数组地址的差是sizeof(someType)的倍数。
  • 元素大小是不必要的(提示:在参数中提到someType)。
  • @Alex 这只是数组本身从sizeof(someType) 的倍数的地址开始的情况。
  • 无论数组从哪里开始,指向数组元素的“中间”都不是一件好事。
  • @zxcdw:不。你不应该关心无效的指针(面对它们你也不能做任何明智的事情)。如果您传递了一个无效指针,那么行为已经未定义,因为您必须首先调用 UB 来获取无效指针
猜你喜欢
  • 2012-08-10
  • 2011-06-07
  • 2021-11-08
  • 2017-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多