`int *userMask[3][4]` 指向什么?

26

我正在修改代码,遇到一个声明,但我有些难以理解:

int *userMask[3][4] = {0};

这个指向确切地指向什么?它是一个每个元素都是指针的矩阵吗?还是指向大小为[3][4]的矩阵?

谢谢


我想我的问题是,当userMask[2][maskElement][user]被声明为int时,它是如何工作的。难道userMask不必是int []才能正常工作吗?我一定是没有理解对...

顺便说一下,感谢你关于cdecl的建议,但是有人知道如何在XP命令提示符中使用它吗?我只能得到语法错误:(

9个回答

43

简短回答

如果已经声明了userMask变量为

int *userMask[3][4];

那么userMask的类型为int*[3][4]。它是一个指向int的2D数组。外部维度的大小为3,内部维度的大小为4。实际上,这只是一个由3个元素组成的1D数组,其中每个元素的类型都是另一个由4个元素组成的1D数组,其元素类型是int*

步骤解释

因此,如果您执行以下操作:

userMask[2][maskElement][user]

然后,基本上你使用前两个索引从2D数组中选择特定的指针:

int * p = userMask[2][maskElement];

然后您可以通过执行 int 类型的偏移量来选择指针上的某个位置,如下所示:

p[user]

现在所有的代码都在userMask[2][maskElement][user]中。

合法的C代码

为了一步步地使用合法的C代码实现它(如果您还不理解以下内容也不用担心):

int * userMask[3][4] = { { 0 } };
int ** pa = userMask[2]; /* int*[4] becomes int** implicitly */
int * pi = pa[maskElement];
int i = pi[user];

assert(i == userMask[2][maskElement][user]);

数组和指针的区别

我认为我向您展示了一些重要的内容。上面的数组不包含指向数组的指针。让我们看看它们的行为有多不同,这是许多 C 程序员没有预料到的:

int array[5][4][3];
/* int[4][3] implicitly converts to int(*)[3] (pointer to first element) */
int (*parray)[3] = array[0]; 
int ** pint = (int**) array[0]; /* wrong!! */

现在,如果我们执行 parray[1]pint[1] 会发生什么呢?前者将使指针parray前进sizeof(int[3])字节(即3 * sizeof(int)),后者只会前进sizeof( int* )字节。所以虽然第一个可以得到正确的数组值array[0][1],但第二个将给出( char * )array[0] + sizeof( int* ),这不是我们想要的结果。但获取错误的偏移量还不是全部问题。由于它不知道正在访问一个数组,它会尝试将pint[1]解释为一个int*类型。假设你的数组初始化为0x00。那么接下来它将基于地址0x00进行下一个索引步骤(例如执行pint[1][0])。哦,不好了——完全未定义的行为!因此强调这种差异非常重要。
结论 这比你要求的更多,但我认为这些细节非常重要。特别是如果你想将2D数组传递给函数,那么这些知识真的很有用。

如果是这样的话,我仍然有点困惑。userMask数组稍后被用作:if(userMask[2][maskElement][user] && blah) result = true; 那么指向int的指针如何像这样通过[user]引用?它不是一个int数组,而是一个int,对吗? - Tim
OP 问的是 C,不是 C++。 - Robert Gamble
1
抱歉,我没注意到。下次我会更仔细阅读的 :) - Johannes Schaub - litb

18

这是一个二维数组,其中每个元素都是指向 int 的指针,并且所有指针都被初始化为零。

在您的后续操作中,您展示了该数组的使用方式:

if(userMask[2][maskElement][user] && blah)
    result = true;

在这种情况下,userMask 中的每个元素实际上应该指向一个 int 数组。(一个 int* 可以指向单个的 int 或者是一组 int)。为了确定这一点,请检查分配给 userMask 的值的代码。例如,可以编写如下代码:

int userArray[2] = { 10, 20 };

userMask[0][0] = userArray; // userMask[0][0] points to the
                            // first element of userArray.

接下来的代码将索引到 userArray

int value = userMask[0][0][1]; // sets value = userArray[1], giving 20.

12
int *userMask[3][4] = {0};

是一个二维数组,其中每个成员都是指向整数的指针。此外,所有成员都初始化为null指针。

int (*userMask)[3][4];

这将是一个整型二维数组的指针。在C语言中,方括号比星号优先级更高,因此需要使用括号来创建数组指针。

cdecl是一个简单的工具,可以用来解释复杂的声明:

cdecl> explain int *userMask[3][4]
declare userMask as array 3 of array 4 of pointer to int

它也可以执行相反的功能:

cdecl> declare userMask as pointer to array 3 of array 4 of int
int (*userMask)[3][4]

所有成员在未初始化时都为null。所有成员在初始化时都被赋值为0。即使这只是微小的差别,但它确实存在。 - tloach
1
@tloach,很抱歉,你说的话我完全听不懂。除非变量是静态的,否则C语言不会自动初始化变量。至于将指针初始化为0或null之间的区别,我不知道你在想什么,但实际上是没有区别的。 - Robert Gamble

3
if(userMask[2][maskElement][user] && blah)
   result = true;

这里的第二部分是,C语言中没有数组;只有指针算术运算。按照定义,p[i] 总是等价于 *(p+i),因此
userMask[2][maskElement][user]

等同于

*((userMask[2][maskElement])+user)

代码中某处正在将一个向量(我打赌它是从malloc(3c)或类似调用中获取的)分配给该数组中的指针;现在你的if语句在说: 如果userMask [2] [maskElement]的向量的用户元素非零 那么如果blah是非零的(由于&&的短路评估,如果第一个结合词为0,则不评估第二个结合词) 那么将结果设置为true。

2

运用内外原则。

int *userMask[3][4] = {0};

从声明的内部开始,
userMask

是名称

userMask[3] 

为它们分配空间(是一个向量),共有3个元素

userMask[3][4] 

为4个userMask[3]分配空间。

int *

告诉我们userMask项是指向int类型的指针。

然后= {0}是一个初始化器,其中所有元素都是0

int *userMask[3][4] = {0};

这是一个3x4的int *数组,初始值为0。


0

我认为该语句访问了usermask数组的第三行,然后访问了该行中的maskElement指针,由于它是一个int指针,因此它可以指向int数组的开头(类似于字符串),我假设它正在这样做,并且该数组由user进行子索引。


0

userMask[2] 的类型是 int*[]
userMask[2][maskElement] 的类型是 int*
因此 userMask[2][maskElement][user] 的类型是 int

声明如下:

int *userMask[3][4] = {0};

是……的简写

int *userMask[3][4] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};

其中每个零都会被隐式转换为(int*)0


0

如果你这样阅读它会有所帮助:

type variablename[array_spec];

在这种情况下: int* usermask[3][4];
所以它是一个 int* 的矩阵。
现在,由于 C 不能区分指针和数组,您可以在指针上使用数组索引。
int* i;
int the_int_behind_i = *(i+1);
int also_the_int_behind_i = i[1];

这需要 i 指向一个区域,其中有几个整数排成一行,当然,就像数组一样。

请注意,上述示例中使用的索引运算符[]看起来像第一次使用的数组规范,但二者是完全不同的。

因此:userMask[2][maskElement][user]

选择存储在 [2][maskElement] 中的用户掩码指针,并针对用户 user 进行评估。


-1

这是一个每个元素都是指针的矩阵。

如果它指向一个大小为[3][4]的矩阵,那么代码应该是

int userMask[3][4]={0};

如果它指向一个大小为[3][4]的矩阵,那么必须是 int (*userMask)[3][4] = 0; 这是一个指向大小为[3][4]的矩阵的指针,初始化为NULL。 - Sundar R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接