指针声明基础(多维数组指针的赋值)

时间:2016-04-29 17:43:47

标签: c++ c arrays pointers

我在函数内部遇到了这个结构(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不是数组本身而是指向数组的指针吗?

2 个答案:

答案 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 + 1int(假设为4字节0x8000 + sizeof (int [3])类型)。

请注意,0x800c的优先级高于一元int,因此表达式[]将被解析为*,其结果为*parr[1]

这不是我们想要的。要通过*(parr[1])访问*(0x800c),我们必须确保{<1}}在应用下标操作之前已取消引用,方法是明确将arr[1]运算符分组括号:parrparr评估为*,其类型为“3元素数组(*parr)[1]”;然后,我们访问该数组的第二个元素(*parr0x8000)以获得所需的值。

现在,让我们看一下 - 如果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];

然后要访问aT (*)[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指针。

<小时/>

  1. 这是令人困惑的地方;数组不是指针,它们不会在内部存储任何指针。相反,数组表达式不是parr[i][j]或一元parr[i]运算符的操作数,其类型从“{元素数组parr”转换为“指向{{1的指针” “和”,表达式的值是数组的第一个元素的地址。这就是您可以在数组和指针对象上使用sizeof运算符的原因。

    这也是我们使用*运算符在我们的代码段中获取 arr 的地址的原因。如果它不是`&amp;`运算符的操作数,则表达式从“T的3元素数组”到“指向T的指针”“衰减”