开发者社区> 问答> 正文

指针比较在C中如何工作?比较不指向同一数组的指针是否可以?

在K&R(C编程语言第二版)第5章中,我阅读了以下内容:

首先,可以在某些情况下比较指针。如果p和q指向同一个数组的成员,则关系一样==,!=,<,>=,等正常工作。

这似乎暗示着只能比较指向同一数组的指针。

但是当我尝试这段代码时

char t = 't';
  char *pt = &t;
  char x = 'x';
  char *px = &x;

  printf("%d\n", pt > px);

1 被打印到屏幕上。

首先,我以为我会得到未定义或某种类型或错误的信息,因为pt和px没有指向同一数组(至少在我的理解中)。

同样是pt > px因为两个指针都指向存储在堆栈中的变量,并且堆栈变小,所以的内存地址t大于x?的内存地址。这是为什么pt > px呢?

引入malloc时,我会更加困惑。同样,在K&R的8.7章中,内容如下:

但是,仍然有一个假设,即sbrk可以有意义地比较指向返回的不同块的指针。该标准不能保证这一点,该标准仅允许在数组内进行指针比较。因此,此版本malloc仅可在通用指针比较有意义的机器之间移植。

将指向堆上分配的空间的指针与指向堆栈变量的指针进行比较,我没有任何问题。

例如,以下代码可以很好地工作并1可以打印:

char t = 't';
 char *pt = &t;
 char *px = malloc(10);
 strcpy(px, pt);
 printf("%d\n", pt > px);

根据对编译器的实验,我被认为可以将任何指针与任何其他指针进行比较,无论它们分别指向何处。而且,我认为两个指针之间的指针算法都很好,无论它们分别指向何处,因为该算法只是使用指针存储的内存地址。

不过,我对在K&R中阅读的内容感到困惑。

我问的原因是因为我的教授。实际上使它成为一个考试问题。他给出了以下代码:

struct A {
    char *p0;
    char *p1;
};

int main(int argc, char **argv) {
    char a = 0;
    char *b = "W";
    char c[] = [ 'L', 'O', 'L', 0 ];

    struct A p[3];
    p[0].p0 = &a;
    p[1].p0 = b;
    p[2].p0 = c;

    for(int i = 0; i < 3; i++) {
        p[i].p1 = malloc(10);
        strcpy(p[i].p1, p[i].p0);
    }
}

然后问什么

p[0].p0 < p[0].p1
p[1].p0 < p[1].p1
p[2].p0 < p[2].p1

评估为。答案是0,1和0。

展开
收起
几许相思几点泪 2019-12-29 20:46:53 5594 0
2 条回答
写回答
取消 提交回答
  • char t = 't'; char *pt = &t; char x = 'x'; char *px = &x;

    printf("%d\n", pt > px); pt 的值是变量t的地址,px的值是变量x的地址。 在程序执行时,是变量x在变量t 后,所以x地址> t地址。 上面的printf 输出0

    2020-02-29 16:10:09
    赞同 展开评论 打赏
  • 比较指向两个相同类型的不同数组的指针的主要问题是,数组本身不需要放置在特定的相对位置中-一个可以在另一个之前和之后结束。

    首先,我以为我会得到未定义或某种类型或错误的信息,因为pt和px并不指向同一数组(至少在我看来)。

    不,结果取决于实施和其他不可预测的因素。

    pt> px也是因为两个指针都指向存储在堆栈中的变量,并且堆栈变小,所以t的内存地址大于x的内存地址吗?为何pt> px为真?

    不一定有堆栈。当它存在时,它不需要长大。它可能长大。它可能以某种奇怪的方式是不连续的。

    而且,我认为两个指针之间的指针算法都很好,无论它们分别指向何处,因为该算法只是使用指针存储的内存地址。

    让我们看一下第85页的C规范 §6.5.8,其中讨论了关系运算符(即,您正在使用的比较运算符)。请注意,这不适用于直接!=或==比较。

    比较两个指针时,结果取决于所指向对象的地址空间中的相对位置。...如果所指向的对象是同一聚合对象的成员,则...指向具有较大下标值的数组元素的指针比指向具有较低下标值的相同数组的元素的指针要大。

    在所有其他情况下,行为是不确定的。

    最后一句话很重要。虽然我减少了一些无关的情况以节省空间,但有一种情况对我们很重要:两个数组,而不是同一struct / aggregate对象的一部分,并且我们正在比较指向这两个数组的指针。这是未定义的行为。

    虽然您的编译器只是插入了某种CMP(比较)机器指令,可以对指针进行数值比较,但是您在这里很幸运,UB是非常危险的野兽。从字面上看,任何事情都可能发生-您的编译器可以优化整个函数,包括可见的副作用。它可能会产生鼻恶魔

    2019-12-29 20:47:08
    赞同 展开评论 打赏
问答分类:
问答标签:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载