【问题标题】:Problems with 2 D arrays二维数组的问题
【发布时间】:2012-09-13 19:32:56
【问题描述】:

我用 C 写了以下代码:

#include<stdio.h>

int  main()
{
  int a[10][10]={1};
  //------------------------
  printf("%d\n",&a);
  printf("%d\n",a);
  printf("%d\n",*a);
  //-------------------------
  printf("%d",**a);

  return 0;
}

通过上述 3 个 printf 语句,我得到了相同的值。在我的机器上它是 2686384。但是最后一条语句我得到了 1。

是不是出了点问题?这些陈述的意思是:

  1. a的地址是2686384
  2. a中存储的值为2686384
  3. a 指向的变量地址(即 2686384)存储的值为 2686384。

这意味着a 必须类似于指向自身的变量...

那为什么*(*a)的输出是1呢?为什么不评价为*(*a)=*(2686384)=2686384

【问题讨论】:

标签: c arrays pointers 2d


【解决方案1】:

首先,如果您想打印出指针值,请使用%p - 如果您使用的是 64 位机器,int 几乎可以肯定小于指针。

**a 是对实际上是 int** 的双重取消引用,因此您最终会得到第一个子数组的第一个元素:1。

【讨论】:

  • 但是 y *a, a 给出相同的值...??
【解决方案2】:

由数组名称组成的表达式可以衰减为指向数组第一个元素的指针。所以即使a 的类型为int[10][10],它也可以衰减为int(*)[10]

现在,这种衰减发生在表达式*a 中。因此表达式的类型为int[10]。重复同样的逻辑,这又会衰减到int*,所以**aint,而且是数组a的第一个元素,即1

另外三个打印语句分别打印出数组的地址,数组的第一个元素,数组第一个元素的第一个元素(当然都是相同的地址,只是类型不同)。

【讨论】:

  • 这里的问题是a和*a如何与**a共享相同的内存位置。
  • @ShobhitSaxena:他们没有。相反,&amp;aa*a 具有相同的数字 ,表示 **a 的位置。原因与“特拉法加广场”、“伦敦”和“英国”都是对我当前位置的正确描述的原因相同。
【解决方案3】:

如果您将a 定义为T a[10](其中T 是某个typedef),那么简单朴素的a 表示数组开始的地址,与&amp;a[0]。他们都有T*的类型。

&amp;a也是数组的起始地址,但类型为T**

在存在多维数组的情况下,事情变得更加棘手。要查看发生了什么,使用 typedef 将事情分解成更小的块更容易。所以,你有效地写了

typedef int array10[10];
array10 a[10];

[给读者练习:a的类型是什么? (不是int**)]

**a 正确计算为数组 a 中的第一个 int

【讨论】:

    【解决方案4】:

    来自 C99 标准

    考虑由声明定义的数组对象

    int x[3][5];
    

    这里的 x 是一个 3 × 5 的整数数组;更准确地说,x 是一个由三个元素对象组成的数组,每个对象都是一个由五个整数组成的数组。在表达式 x[i] 中,它等价于 (*((x)+(i))),x 首先被转换为指向五个整数的初始数组的指针。然后根据 x 的类型调整 i,这在概念上需要将 i 乘以指针指向的对象的大小,即由五个 int 对象组成的数组。添加结果并应用间接以产生五个整数的数组。当在表达式 x[i][j] 中使用时,该数组又被转换为指向第一个 int 的指针,因此 x[i][j] 产生一个 int。

    所以,

    初始数组将仅为 x[0][0]。

    所有 x、&x 和 *x 都将指向 x[0][0]。

    【讨论】:

      【解决方案5】:

      不,您的代码没有任何问题。就像你想的那样……我想得越多,我就越难以解释,所以在我开始讨论之前,请记住以下几点:

      1. 数组不是指针,别这么想,它们是不同的类型。
      2. [] 是一个运算符。这是一个移位和顺从运算符,所以当我写 printf("%d",array[3]); 时,我是在移位和顺从

      所以一个数组(让我们考虑一维开始)在内存中的某个地方:

      int arr[10] = {1};
      //Some where in memory---> 0x80001f23
                                  [1][1][1][1][1][1][1][1][1][1]
      

      如果我说:

      *arr; //this gives the value 1
      

      为什么?因为它与arr[0] 相同,它为我们提供了数组开头地址处的值。这意味着:

      arr; // this is the address of the start of the array
      

      那么这给了我们什么?

      &arr; //this will give us the address of the array. 
            //which IS the address of the start of the array
            //this is where arrays and pointers really show some difference
      

      所以arr == &amp;arr;。数组的“工作”是保存数据,数组不会“指向”其他任何东西,因为它保存着自己的数据。时期。另一方面,指针的作用是指向其他东西:

      int *z;     //the pointer holds the address of someone else's values
      z = arr;    //the pointer holds the address of the array
      z != &z;    //the pointer's address is a unique value telling us where the pointer resides
                  //the pointer's value is the address of the array
      

      编辑: 另一种思考方式:

      int b;   //this is integer type
      &b;      //this is the address of the int b, right?
      
      int c[]; //this is the array of ints
      &c;      //this would be the address of the array, right?
      

      所以这很好理解:

      *c;   //that's the first element in the array
      

      那行代码告诉你什么?如果我尊重c,那么我会得到一个整数。这意味着简单的c 是一个地址。由于它是数组的开头,它是数组的地址,因此:

      c == &c;
      

      【讨论】:

      • 这是我的问题..?? arr==&arr 怎么可能..??你怎么能允许一个指针存储它自己的内存地址,然后多次取消引用它并说存储在 a[0] 的值。
      • @ShobhitSaxena - 你没有在听第 1 点。arr 不是指针。一个数组!=一个指针。故事结局。看看我的编辑。这有帮助吗?我认为这可能更清楚。
      • @ShobhitSaxena 请记住,遵从运算符 (*) 不是特定于指针的东西。它是一个处理内存地址的运算符。我可以这样做:int x = 0; 然后printf("%d",*(&amp;x));,这将毫无意义,但这可以打印 0 并且x 不是指针
      【解决方案6】:

      首先,关于数组的一个词...

      除非它是sizeof_Alignof 或一元&amp; 运算符的操作数0,或者是用于在声明中初始化另一个数组的字符串文字,表达式T”类型的“N-element array of T”将被转换(“decay”)为“指向T”类型的表达式,表达式的值将是数组中第一个元素的地址.

      表达式&amp;a 的类型为“指向int 的10 元素数组的10 元素数组的指针”,或int (*)[10][10]。表达式a 的类型为“int 的 10 元素数组的 10 元素数组”,根据上面的规则,它会衰减为“指向int 的 10 元素数组的指针”,或int (*)[10]。最后,表达式*a(相当于a[0])的类型为“int 的10 元素数组”,根据上面的规则,它再次衰减为“指向int 的指针”。

      所有三个表达式都有相同的值,因为数组的地址和它的第一个元素的地址相同:&amp;a[0][0] == a[0] == *a == @ 987654340@ == &amp;a。但是,表达式的类型是不同的,这在进行指针运算时很重要。例如,如果我有以下声明:

      int (*ap0)[10][10] = &a;
      int (*ap1)[10]     =  a;
      int *ip            = *a;
      

      然后ap0++ 将前进ap0 指向int 的下一个10x10 数组,ap1++ 将前进ap1 指向int 的下一个10 元素数组的指针(或a[1] ),而ip++ 将前进ip 以指向下一个int (&amp;a[0][1])。

      **a 等价于*a[0] 等价于a[0][0]。这是a 的第一个元素的,类型为int,值1(注意 a[0][0] 初始化为@987654361 @; 所有剩余的元素都初始化为0)。

      请注意,您应该使用%p 打印出指针值:

      printf("&a = %p\n", &a);
      printf(" a = %p\n",  a);
      printf("*a = %p\n", *a);
      

      【讨论】:

        【解决方案7】:
        #include<stdio.h>
        
        int  main()
        {
          // a[row][col]
          int a[2][2]={ {9, 2}, {3, 4} };
          // in C, multidimensional arrays are really one dimensional, but
          // syntax alows us to access it as a two dimensional (like here).
        
          //------------------------
          printf("&a            = %d\n",&a);
          printf("a             = %d\n",a);
          printf("*a            = %d\n",*a);
          //-------------------------
        
          // Thing to have in mind here, that may be confusing is:
          // since we can access array values through 2 dimensions,
          // we need 2 stars(asterisk), right? Right.
        
          // So as a consistency in this aproach,
          // even if we are asking for first value,
          // we have to use 2 dimensional (we have a 2D array)
          // access syntax - 2 stars.
        
          printf("**a           = %d\n", **a );         // this says a[0][0] or *(*(a+0)+0)
          printf("**(a+1)       = %d\n", **(a+1) );     // a[1][0] or *(*(a+1)+0)
          printf("*(*(a+1)+1)   = %d\n", *(*(a+1)+1) ); // a[1][1] or *(*(a+1)+1)
          // a[1] gives us the value on that position,
          // since that value is pointer, &a[i] returns a pointer value
          printf("&a[1]         = %d\n", &a[1]);
          // When we add int to a pointer (eg. a+1),
          // really we are adding the lenth of a type
          // to which pointer is directing - here we go to the next element in an array.
        
          // In C, you can manipulate array variables practically like pointers.
          // Example: littleFunction(int [] arr) accepts pointers to int, and it works vice versa,
          //          littleFunction(int* arr) accepts array of int.
        
          int b = 8;
          printf("b             = %d\n", *&b);
        
          return 0;
        
        }
        

        【讨论】:

          猜你喜欢
          • 2019-08-08
          • 2011-04-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-08
          • 2011-03-18
          • 2013-03-24
          相关资源
          最近更新 更多