【问题标题】:Pointer Arithmetic - Issues with array and pointer to an array指针算术 - 数组和指向数组的指针的问题
【发布时间】:2020-05-07 08:09:00
【问题描述】:

我最近切换到 C 并试图找出指针。

#include <stdio.h>

int main()
{
    int arr[5] = {1,2,3,4,5};
    int *a = &arr;

    printf("Array : %p\n", arr);
    for(int i=0; i<5; i++)
    {
        printf("Value and Address of Element - %d : %d\t%p,\n", i+1, arr[i], &arr[i]);
    }
    printf("Pointer to the Array : %p\n", a);
    printf("Value pointed by the pointer : %d\n", *a);
    a = (&a+1);
    printf("Pointer after incrementing : %p\n", a);
    return 0;
}

但是,以下行似乎不起作用。

a = (&a+1);

打印指针a的递增值后,它仍然指向数组(arr)。 这是程序的输出:

Array : 0x7ffe74e5d390
Value and Address of Element - 1 : 1    0x7ffe74e5d390,
Value and Address of Element - 2 : 2    0x7ffe74e5d394,
Value and Address of Element - 3 : 3    0x7ffe74e5d398,
Value and Address of Element - 4 : 4    0x7ffe74e5d39c,
Value and Address of Element - 5 : 5    0x7ffe74e5d3a0,
Pointer to the Array : 0x7ffe74e5d390
Value pointed by the pointer : 1
Pointer after incrementing : 0x7ffe74e5d390

如您所见,指针“a”仍指向第一个元素。但是,理论上不应“a”指向最后一个元素之后的任何内容(鉴于 &a + 1 将指针增加整个数组的大小 - 来源:difference between a+1 and &a+1

有人能解释一下原因吗?

【问题讨论】:

  • int *a = &amp;arr; 不应编译。
  • C 和 C++ 是不同的语言,没有一种语言叫做“C/C++”。
  • 确保启用所有警告,并将警告视为错误,特别是如果您是这些语言的初学者。即便如此,C 和 C++ 都有很多方法可以编写仍然未被编译器拒绝的无效程序。
  • @molbdnilo 不确定,但我可以想象它在 C 中很好。
  • godbolt.org 上尝试使用多个编译器编写代码可能会有所帮助 - 通常错误消息会有所不同,并且某些编译器会比其他编译器更清楚地传达问题。

标签: c++ c arrays pointers pointer-arithmetic


【解决方案1】:

a = (&amp;a+1);a 设置为指向a 的地址之外的一个“事物”。

之前,您的代码使用int *a = &amp;arr;a 设置为&amp;arr。 (这违反了标准 C 约束,因为 &amp;arr 的类型是指向数组的指针,而不是指向 int 的指针。正确的定义是 int *a = arr;。)我怀疑您在 a = (&amp;a+1); 中的意图是设置a 指向一个超出当前指向的位置。但是,正确的代码是a = a+1;。这需要a,将其加一,然后将结果分配给a。 相反,a = (&amp;a+1); 使用a 的地址而不是它的值。

这导致a 指向内存中a 之外的任何位置。在您的实验中,似乎数组 arr 恰好在那里,并且您的 C 实现也有相应的行为。

(这解释了您观察到的结果,但这不是您应该依赖的行为。C 标准没有定义当您以这种方式滥用指针时会发生什么,并且包括编译器优化在内的各种事情都会导致程序运行好像&amp;a+1 没有指向arr,即使arr 实际上位于内存中的地址&amp;a+1。)

【讨论】:

  • 好吧,这很有意义。太感谢了。是的,我的意图是使'a'指向超出数组绑定的内存位置。这也是我决定学习 C++ 的原因之一,这样我就可以了解事物在较低级别是如何工作的(内存是如何工作的)。
【解决方案2】:

在这种特殊情况下,变量和数组可能会像下面那样放在堆栈上,标准不保证这一点。每个单元格都是整数。你还记得每个放置的本地变量的堆栈地址都会减少吗?

+-+-+-+-+-+-+
|a|1|2|3|4|5|
+-+-+-+-+-+-+

&amp;a+1,不是数组的地址,你取a的地址,移动一个单元格得到数组的地址。

【讨论】:

  • 是的,这是对许多流行平台上观察到的行为的合理解释。但是,我们无法保证。
  • @S.M.这正是我认为它也会做的事情。但后来我找到了这个解释link,并想知道是什么导致它的行为不同。
  • @RonnyRoy 与该问题的不同之处在于您将指向数组的指针分配给int* 类型的变量(这会引发警告)。由于这一步,您丢失了它曾经是大小为 5 的数组的类型信息,并且在 int**(在 (&amp;a+1) 中)上执行了算术运算。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-07
  • 2023-03-11
  • 1970-01-01
  • 2016-07-30
相关资源
最近更新 更多