【问题标题】:Pointer to array has the same value as array指向数组的指针与数组具有相同的值
【发布时间】:2015-03-20 08:11:27
【问题描述】:

下面的代码创建了一个数组和一个指向它的指针。然后程序打印出这两个变量的内容。奇怪的是,打印出来的内存地址是相同的,即使它们不应该。 ptr 应该包含array地址,而不是array 本身。有人可以解释一下吗?

#include <stdio.h>

int main() {

    char array[] = "abcdefg";
    char (*ptr)[] = &array;

    printf("%p\n", array);
    printf("%p\n", ptr);
}

【问题讨论】:

  • 您的第一个 printf 调用也会打印数组的地址。
  • @immibis 你能详细说明一下吗?
  • array 在大多数情况下由编译器转换为 &amp;array[0]
  • 查找数组到指针衰减

标签: c arrays pointers


【解决方案1】:

对于任何名为arrayarray&amp;array 的数组具有相同的值——数组的第一个元素的地址。只是它们的类型不同 - array 这里有 char * 类型,&amp;arraychar(*)[] 类型。

【讨论】:

    【解决方案2】:

    例如,将数组视为char a[10];

    当我们分配指针变量时,我们分配为char *ptr=a

    我们也可以像ptr=&amp;a[0];这样赋值,所以两个语句是相同的,两个将引用数组的起始地址

    【讨论】:

      【解决方案3】:

      根据 Eli Bendersky 的 Pointers to arrays in C

      考虑这段代码:

      void test(int** p)
      {
      }
      
      int main()
      {
          int arr[] = {30, 450, 14, 5};
          test(&arr);
          return 0;
      }
      

      gcc 对此不太满意,并发出警告:passing arg 1 of test from incompatible pointer type。 C++ 有更严格的类型 检查,所以让我们尝试通过g++ 运行相同的代码。作为 预期,我们得到一个错误:cannot convert int (*)[4] to int** for argument 1 to void test(int**)

      那么这里的问题是什么?上面的代码有什么问题?好, 一切。这简直是​​无效的,没有任何意义。有些人会 认为它应该有效,因为它有效:

      void test(int* p)
      {
      
      }
      
      int main()
      {
          int arr[] = {30, 450, 14, 5};
          test(arr);
          return 0;
      }
      

      但是这个特别有效,因为 C 编译器应该遵循 C标准,它要求数组“衰减”成指针,当 用作左值。因此,指向数组第一个元素的指针是 实际上通过了测试,一切正常。

      但是,第一个代码sn-p是不同的。虽然数组名称可能 衰减成指针,数组的地址不会衰减成 指向指针的指针。为什么要这样做?它有什么意义 这么对待数组?

      有时会传递指向指针的指针来修改指针 (简单的指针参数在这里不起作用,因为 C 按值传递, 这只允许修改指向的内容,而不是指针 本身)。这是一些虚构的代码(不会编译):

      void test(int** p)
      {
          *p = malloc ... /* retarget '*p' */
      }
      
      int main()
      {
          int arr[] = {30, 450, 14, 5};
          int* ptr;
      
          /* Fine!
          ** test will retarget ptr, and its new value
          ** will appear after this call.
          */
          test(&ptr);
      
          /* Makes no sense!
          ** You cannot retarget 'arr', since it's a
          ** constant label created by the compiler.
          */
          test(&arr);
      
          return 0;
      }
      

      指向数组的指针

      请注意,原始代码可以稍作修改以使其成为 工作:

      void test(int (*p)[4])
      {
          (*p)[2] = 10;
      }
      
      int main()
      {
          int arr[] = {30, 450, 14, 5};
      
          test(&arr);
          printf("%d\n", arr[2]);
      
          return 0;
      }
      

      现在那个奇怪的类型测试接受了什么?向“指向 数组”,C 的无用特性之一。这就是 C 常见问题解答的内容 说一下:

      2.12:如何声明指向数组的指针?

      通常,您不想这样做。当人们随便谈论一个指向 一个数组,它们通常表示指向其第一个元素的指针。

      虽然前面的 sn-p 中的测试函数编译并工作, 它没有多大用处,因为它写起来更清晰:

      void test(int* p)
      {
          p[2] = 10;
      }
      
      ...
      ...
      /* then call */
      test(arr);
      

      指针作为函数参数的主要用途是避免 按值传递整个结构,或修改指向的对象 指针。对于指向数组的指针,两者都无关紧要。这里是 一个澄清的sn-p:

      int joe[] = {1, 2, 3, 4};
      
      void test(int (*p)[4])
      {
          /* Fine: assign to an element through the
          ** pointer.
          */
          (*p)[2] = 10;
      
          /* Works, but won't be reflected in the
          ** caller since p was passed by value.
          */
          p = &joe;
      
          /* Error: arrays can't be assigned.
          */
          *p = joe;
      }
      

      数组不是按值传递的,所以指向数组的指针是 对这个目的没用。数组也不能被修改,所以 杀死第二个原因。

      为了回答这个问题,&amp;array 等于array 的原因是因为array 是“由编译器创建的常量标签”,而不是指针变量。因此,“取消引用”array 实际上是没有意义的,并且编译器恰好在发生这种情况时简单地返回 array 本身的值。

      【讨论】:

        【解决方案4】:

        array 没有地址,就像ptr 有地址一样。因为数组总是指向同一个内存位置,所以不需要将该内存位置存储在某个 other 内存位置。没有办法使用array 并获得一个临时的char** 这样(*char)[0] == 'a'

        所以&amp;array 的类型为char(*)[],并返回数组中第一个char 的位置。同样,array 在指针上下文中使用时(也就是说,几乎在任何地方,除了几个例外),与&amp;array 具有相同的效果,但类型不同。这被称为“阵列衰减”。

        更多信息请访问What is array decaying?

        【讨论】:

        • "数组没有地址" 每个变量都有一个地址。它的值不是地址。 “因为数组总是指向同一个内存位置” 数组是元素的序列;它没有“指向”。 “没有办法获取数组并获取临时字符**” 对,因为这是指向指针的指针,而不是指向数组的指针。 “所以 &array 的类型为 char(*)[],并返回数组中第一个字符的位置。”不,它返回一个指向数组的指针。
        猜你喜欢
        • 1970-01-01
        • 2015-09-11
        • 2016-01-27
        • 2018-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-07
        • 2017-09-03
        相关资源
        最近更新 更多