我在函数内部遇到了这个结构(e是传递给函数的参数):
short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]);
及其用法(其中i是for循环中的计数器):
(*tt)[i][0]
我想我得到了作业的第一部分:
short (*tt)[][2]
根据我的理解tt被声明为指向一组short数组的指针。 第二部分令我感到困惑,看起来像是某种演员,但我不确定我理解它的作用,尤其是:(*)。它是如何工作的?
heater_ttbl_map被声明为这样(其中pointer1和pointer2都是shortimensional shortet数组):
static void *heater_ttbl_map[2] = {(void*)pointer1, (void*)pointer2};
至于它的用法我理解tt指向的是dereferenced(它是数组的i索引的第三个索引的内容,这是一个简短的),但为什么写这样:
(*tt)[i][0]
而不是这样:
*tt[i][0]
是因为tt不是数组本身而是指向数组的指针吗?
答案 0 :(得分:5)
由于运算符优先级([]
优先于*
运算符),两个语句存在差异 -
(*tt)[i][0]
在此处,您可以访问指针[i][0]
所指向的数组的索引tt
处的元素。
然而,在此 -
*tt[i][0]
首先访问索引[i][0]
(可能是指针的二维数组)的元素,然后取消引用。
交替使用它们会导致访问或取消引用未经授权的内存位置并导致未定义的行为。
答案 1 :(得分:2)
正如ameyCU所解释的那样,[]
下标运算符的优先级高于一元*
运算符,因此表达式*a[i]
将被解析为{{1 }}; IOW,您正在索引*(a[i])
并取消引用结果。
如果a
是一个a
数组(或指向T
的数组),则此方法有效;下方有更多内容。但是,如果T
是指向a
的数组的指针,则无法执行您想要的操作。这可能是最好的视觉解释。
假设声明:
T
以下是内存中的内容(有点类似;地址是凭空消失的):
int arr[3] = { 0, 1, 2 };
int (*parr)[3] = &arr; // type of &arr is int (*)[3], not int **
所以你看到数组Address Item Memory cell
------- ---- -----------
+---+
0x8000 arr: | 0 | <--------+
+---+ |
0x8004 | 1 | |
+---+ |
0x8008 | 2 | |
+---+ |
... |
+---+ |
0x8080 parr: | | ----------+
+---+
...
有三个元素,指针arr
指向parr
。我们希望通过指针arr
访问arr
的第二个元素(地址1
的值0x8004
)。如果我们写parr
会怎么样?
首先,请记住表达式*parr[1]
定义为a[i]
;也就是说,给定指针值*(a + i)
1 ,从{{1}偏移a
元素(不是字节)并取消引用结果。但是从i
偏移a
元素是什么意思?
指针算法基于指向类型的大小;如果i
是指向a
的指针,那么p
将为我提供T
类型的下一个对象的位置。因此,如果p+1
指向地址T
处的p
对象,则int
会在0x1000
之后显示p+1
对象的地址 - int
。
所以,如果我们写p
,那会给我们带来什么?由于0x1000 + sizeof (int)
指向parr[1]
的3元素数组,parr
将为我们提供int
的下一个 3元素数组的地址 - parr + 1
或int
(假设为4字节0x8000 + sizeof (int [3])
类型)。
请注意,0x800c
的优先级高于一元int
,因此表达式[]
将被解析为*
,其结果为*parr[1]
。
这不是我们想要的。要通过*(parr[1])
访问*(0x800c)
,我们必须确保{<1}}在应用下标操作之前已取消引用,方法是明确将arr[1]
运算符分组括号:parr
。 parr
评估为*
,其类型为“3元素数组(*parr)[1]
”;然后,我们访问该数组的第二个元素(*parr
或0x8000
)以获得所需的值。
现在,让我们看一下 - 如果int
等同于0x8000 + sizeof (int)
,那么0x8004
等同于a[i]
。这意味着我们可以将*(a+i)
写为a[0]
,或仅*a
。现在,您不希望为此情况执行此操作,因为(*parr)[1]
只是指向1D数组的指针,而不是2D数组。但这就是2D数组索引的工作原理。给定(parr[0])[1]
之类的声明,在大多数情况下,表达式parr[0][1]
将“衰减”为parr
类型。如果我写了像
T a[M][N];
然后要访问a
到T (*)[N]
的元素,我需要做的就是写int arr[3][2] = {{1,2},{3,4},{5,6}};
int (*parr)[2] = arr; // don't need the & this time, since arr "decays" to type
// int (*)[2]
; arr
隐式取消引用parr
指针。
<小时/>
parr[i][j]
或一元parr[i]
运算符的操作数,其类型从“{元素数组parr
”转换为“指向{{1的指针” “和”,表达式的值是数组的第一个元素的地址。这就是您可以在数组和指针对象上使用sizeof
运算符的原因。
*
运算符在我们的代码段中获取 arr 的地址的原因。如果它不是`&amp;`运算符的操作数,则表达式从“T
的3元素数组”到“指向T
的指针”“衰减”