假设我定义了一个结构并创建了它的一些实例。我有一个指向这些实例的指针数组,但有些指针指向我的结构的相同实例。我想删除数组中的重复项,因此我按qsort()
函数对其进行排序。这是我的比较功能:
int cmp(const void *a, const void *b)
{
struct foo **s1 = (struct foo**)a;
struct foo **s2 = (struct foo**)b;
return *s1 - *s2;
}
问题是,我真的可以使用这样的比较吗?我知道在这种情况下,子构造指针是未定义的,但我只关心指针的整数值,因为我只是希望指向同一个foo
实例的指针彼此相邻。
也许我应该使用这样的函数:
int cmp(const void *a, const void *b)
{
struct foo **s1 = (struct foo**)a;
struct foo **s2 = (struct foo**)b;
if (*s1 > *s2)
return 1;
else if (*s1 == *s2)
return 0;
else
return -1;
}
使用它们有什么不同吗?
答案 0 :(得分:2)
如果您有intptr_t
(这是一个整数类型),那么您可以将void*
指针转换为该指针,然后您可以比较任意值。 intptr_t
不是必需的类型,但在实践中很常见。
从另一个中减去一个intptr_t
可能仍会溢出,因此它不是一个严格的可移植解决方案。但比较还可以。如果您使用uintptr_t
来避免溢出,则差异永远不会为负。这是使用a - b
实现qsort样式比较函数的一般问题。
减去或比较未指向同一对象的指针是未定义的行为。因此,问题中提出的解决方案都不是有效的:
§6.5.6第9段(加法运算符):
当减去两个指针时,两个指针都应指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素
§6.5.8第5段提供了可能的有效比较列表,这比减法的限制更加慷慨,因为您可以将指针与同一struct
或{{1}的两个成员进行比较。如果成员本身属于同一类型。但不相关的对象不属于这个列表中的任何一个。它以句子结束:“在所有其他情况下,行为未定义。”
如果你想要一个不依赖于union
的真正可移植的解决方案,那么你可以记住这些指针。但是,实际上,我认为这只是理论上的兴趣。
答案 1 :(得分:0)
如果要删除重复项,则可以使用嵌套for循环遍历每个指针,如下所示:
int duplicates=0;
for (int i=0;i<count;++i;)
for (int j=i+1;j<count;++j)
if (data [i]==data [j])
++duplicates;
然后为count-duplicates
指针分配足够的内存,然后遍历原始数据集,只复制尚未复制的数据集。它效率低下,但它会起作用。