这是写数组指针的过程

问题描述 投票:0回答:2

这就是写数组指针的过程。

int *pj = *pi;
*pi
是数组的值,为什么没有报错呢? (假设
pi
包含第二行的地址值,我认为
*pi
是5,如果5是地址值?)

我不明白

#include <stdio.h>

int main()
{
    int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

    for(int (*pi)[4]=arr; pi<arr+3; pi++){
        for(int *pj = *pi; pj<*pi+4;pj++){
            printf("%4d",*pj);
        }
        printf("\n");
    }
}
arrays c pointers
2个回答
2
投票

当你引用一个固定数组本身时,它可以decay变成指向它的第一个元素的指针。

arr
是一个
int[3][4]
数组,即3个元素的数组,其中每个元素是一个
int[4]
数组。

pi
是指向
int[4]
数组的指针。

因此:

pi = arr

等于:
pi = &arr[0]

即外部数组中第一个元素的地址。

arr + 3

等于:
&arr[0] + 3
又名
&arr[3]

即外部数组的第三个元素之后的地址。

因此,外层循环遍历元素

arr[0]
..
arr[2]
,其中
pi
在每次迭代中指向当前元素。

pj
是指向
int
的指针。
*pi
产生对当前
int[4]
数组的引用,然后它 decays 成一个
int*
指针指向它的第一个
int
.

因此:

pj = *pi

等于:
pj = &(*pi)[0]

即当前
int
数组中第一个
int[4]
的地址。

*pi + 4

等于:
&(*pi)[0] + 4
又名
&(*pi)[4]

即当前
int
数组中第4个
int[4]
之后的地址。

因此,内部循环遍历元素

(*pi)[0]
..
(*pi)[3]
,其中
pj
在每次迭代中指向当前元素。


也许下面的图表会对你有所帮助。

想想

arr
在内存中是这样布局的(不是真的,但是可以treated好像是):

+----+----+-----+---+
| 1  | 2  | 3  | 4  |
+----+----+----+----+
| 5  | 6  | 7  | 8  |
+----+----+----+----+
| 9  | 10 | 11 | 12 |
+----+----+----+----+

在外循环的第一次迭代中,

pi
指向这里:

   +----+----+-----+---+
-> | 1  | 2  | 3  | 4  |
   +----+----+----+----+
   | 5  | 6  | 7  | 8  |
   +----+----+----+----+
   | 9  | 10 | 11 | 12 |
   +----+----+----+----+

并且在内部循环的每次迭代中,

pj
遍历内部数组:

   +----+----+-----+---+
   | 1  | 2  | 3  | 4  |
   +----+----+----+----+
     ^
   +----+----+-----+---+
   | 1  | 2  | 3  | 4  |
   +----+----+----+----+
          ^
   +----+----+-----+---+
   | 1  | 2  | 3  | 4  |
   +----+----+----+----+
               ^
   +----+----+-----+---+
   | 1  | 2  | 3  | 4  |
   +----+----+----+----+
                    ^

当内循环完成时,外循环的第 2 次迭代运行,其中

pi
现在指向这里:

   +----+----+-----+---+
   | 1  | 2  | 3  | 4  |
   +----+----+----+----+
-> | 5  | 6  | 7  | 8  |
   +----+----+----+----+
   | 9  | 10 | 11 | 12 |
   +----+----+----+----+

并且

pj
现在遍历该内部数组:

   +----+----+----+----+
   | 5  | 6  | 7  | 8  |
   +----+----+----+----+
     ^
   +----+----+----+----+
   | 5  | 6  | 7  | 8  |
   +----+----+----+----+
          ^
   +----+----+----+----+
   | 5  | 6  | 7  | 8  |
   +----+----+----+----+
               ^
   +----+----+----+----+
   | 5  | 6  | 7  | 8  |
   +----+----+----+----+
                    ^

当内循环结束时,外循环的第 3 次也是最后一次迭代运行,其中

pi
现在指向这里:

   +----+----+-----+---+
   | 1  | 2  | 3  | 4  |
   +----+----+----+----+
   | 5  | 6  | 7  | 8  |
   +----+----+----+----+
-> | 9  | 10 | 11 | 12 |
   +----+----+----+----+

并且

pj
现在遍历该内部数组:

   +----+----+----+----+
   | 9  | 10 | 11 | 12 |
   +----+----+----+----+
     ^
   +----+----+----+----+
   | 9  | 10 | 11 | 12 |
   +----+----+----+----+
          ^
   +----+----+----+----+
   | 9  | 10 | 11 | 12 |
   +----+----+----+----+
               ^
   +----+----+----+----+
   | 9  | 10 | 11 | 12 |
   +----+----+----+----+
                    ^

当两个循环都完成时,整个数组已经被迭代,并且每个

int
都被打印出来了。


1
投票

鉴于

arr
...

的定义
    int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

...在

pi
的定义中...

int (*pi)[4]=arr;

,具有数组类型

arr
的子表达式
int[3][4]
,自动转换为指向第一个数组元素的指针。该元素的数组类型为
int[4]
,指向它的指针的类型为
int(*)[4]
,这与为
pi
声明的类型完全匹配。所以一切都很好。

在这种情况下,考虑

pj
的定义:

int *pj = *pi;

pi
的类型是
int(*)[4]
,所以
*pi
的类型是
int[4]
,一个数组类型。因为它有一个数组类型,这个子表达式的值自动转换为指向它的第一个元素的指针,在本例中是一个
int
。指向它的指针具有类型
int *
,它与为
pj
声明的类型完全匹配,所以再一次,一切都很好。

假设

pi
包含第二行的地址值,我认为
*pi
是5.

最后的结论是错误的。

pi
确实包含一行的地址,所以
*pi
指定 整行,而不仅仅是它的一个元素。指针的类型在这里很重要。

© www.soinside.com 2019 - 2024. All rights reserved.