是的,您的检查是正确的,但它肯定不是最有效的(如果“效率”是指计算效率)。您的实现中明显的直观低效率是基于这样一个事实,即当字符串实际重叠时,strlen
调用将迭代它们的公共部分两次。
为了形式上的效率,人们可能会使用一种稍微不同的方法
int are_overlapping(const char *a, const char *b)
{
if (a > b) /* or `(uintptr_t) a > (uintptr_t) b`, see note below! */
{
const char *t = a;
a = b;
b = t;
}
while (a != b && *a != '\0')
++a;
return a == b;
}
关于这个版本的一个重要说明是,它对两个不能保证指向同一个数组的指针进行关系比较,这在形式上会导致未定义的行为。它将在具有平面内存模型的系统上实际工作,但可能会受到迂腐代码审查者的批评。要正式解决此问题,可以uintptr_t
在执行关系比较之前将指针转换为。这样,在大多数(如果不是全部)具有平面内存模型的传统实现中,未定义的行为将转换为具有适当语义的实现定义的行为。
这种方法没有“重复计数”问题:它只分析位于内存中“较早”的字符串的非重叠部分。当然,在实践中,这种方法的好处可能被证明是不存在的。这将取决于您的strlen
实现质量和实际输入的属性之一。
例如,在这种情况下
const char *str = "Very very very long string, say 64K characters long......";
are_overlapped(str, str + 1);
我的版本将比您的版本更快地检测到重叠。我的版本将在循环的 1 次迭代中执行此操作,而您的版本将花费 2 * 64K 次迭代(假设 的简单实现strlen
)。
如果您决定深入到有问题的指针比较领域,上述想法也可以重新实现为
int are_overlapping(const char *a, const char *b)
{
if (a > b)
{
const char *t = a;
a = b;
b = t;
}
return b <= a + strlen(a);
}
此实现不会在每次迭代时执行额外的指针比较。我们为此付出的代价是它总是迭代到其中一个字符串的末尾,而不是提前终止。然而,它仍然比您的实现更有效,因为它只调用strlen
一次。