I have a question asking me to find the offset in bytes between two array element addresses:
我有一个问题要求我找到两个数组元素地址之间的字节偏移量:
double myArray[5][7];
If C stored data in column-major order the offset (in bytes) of
&myArray[3][2]
from&myArray[0][0]
would be:如果C以列主要顺序存储数据,则来自&myArray [0] [0]的&myArray [3] [2]的偏移量(以字节为单位)将为:
In column major order, I think elements would be laid out as such:
在列主要顺序中,我认为元素将如下布局:
[0][0] -- [1][0] -- [2][0] -- [3][0] -- ..... -- [3][2]
So in my mind to get the offset in bytes is to count the number of jumps between [0][0] and [3][2] and times that by 8 since it's an array of doubles. However, what's confusing me is that it's asking for the offset using the & operator. Would this somehow change the answer since it's asking between two addresses or is the process still the same? I think it'd be the same but I'm not 100% certain.
所以在我看来,以字节为单位的偏移量是计算[0] [0]和[3] [2]之间的跳跃次数,以及8次的跳跃次数,因为它是一个双精度数组。然而,令我困惑的是它使用&运算符要求偏移量。这会以某种方式改变答案,因为它在两个地址之间询问或者流程是否仍然相同?我认为它是一样的,但我不是100%肯定。
If my thinking is correct would this then be 8*15 bytes?
如果我的想法是正确的,那么这将是8 * 15字节?
3 个解决方案
#1
3
The memory lay out for the 2d array would be a contiguous chunk of memory.(Based on your question)
2d阵列的内存布局将是一块连续的内存。(基于你的问题)
int x[2][3] = {{0,1,2},{3,4,5}};
That will be layed out in (Your question)
这将在(你的问题)中列出
--+--+--+--+--+--+
0| 3| 1| 4|2 |5 |
--+--+--+--+--+--+
But in C
this is stored like
但在C中,这就像存储一样
--+--+--+--+--+--+
0| 1| 2| 3|4 |5 |
--+--+--+--+--+--+
Now you are absolutely right, that you can consider jumps between [0][0]
and [3][2]
but there is a better way to do that without thinking about all this, you can be sure that their offset will be their address differences.
现在你是绝对正确的,你可以考虑在[0] [0]和[3] [2]之间跳转但是有一个更好的方法来做到这一点而不考虑所有这些,你可以确定他们的偏移将是他们的解决差异。
You can simply get their addresses and subtract them.
您只需获取地址并减去它们即可。
ptrdiff_t ans = &a[3][2]-&a[0][0]
;(this is basically the gaps between the two elements)
ptrdiff_t ans =&a [3] [2] - &a [0] [0];(这基本上是两个元素之间的差距)
That yields the answer. printf("answer = %td",ans*sizeof(a[0][0]);
(One gap = sizeof(a[0][0])
) [In your case double
]
这就产生了答案。 printf(“answer =%td”,ans * sizeof(a [0] [0]);(一个间隙= sizeof(a [0] [0]))[在你的情况下为双]
Or even better way would be to
或者甚至更好的方式
ptrdiff_t ans = (char*)&a[3][2] - (char*)&a[0][0];//number of bytes between them.
I will explain a bit why char*
is important here:
我将解释一下为什么char *在这里很重要:
(this is not general enough)(char*)&a[0][0]
and
&a[0][0]
both contain the same thing
value-wise.
(char *)&a [0] [0]和&a [0] [0]都包含值相同的东西。 (这不够通用)
But it matters in pointer arithmetic. (Interpretation is different).
但它在指针算术中很重要。 (解释不同)。
When not using the cast, the interpretation is of the data type of array elements. That means now it consider the difference in double
s. When you cast it, it spits the result in or difference in char
-s.
不使用强制转换时,解释是数组元素的数据类型。这意味着现在考虑双打的差异。当你施放它时,它会将结果吐出或者不同于char-s。
And why this works? Because all data memory is byte
addressable and char
is of single bytes.
为什么这个有效?因为所有数据存储器都是字节可寻址的,而char是单字节的。
There is something more to this than expected , first let's see what is an array in C
? †
除此之外还有更多的东西,首先让我们看看C中的数组是什么? †
C does not really have multi-dimensional arrays. In C
it is realized as an array of arrays. And yes those multidimensional array elements are stored in row-major order.
C实际上没有多维数组。在C中,它被实现为数组阵列。是的,那些多维数组元素以行主顺序存储。
To clarify a bit more we can look into an example of standard §6.5.2.1
为了澄清一点,我们可以看一下标准§6.5.2.1的例子
Consider the array object defined by the declaration
考虑声明定义的数组对象
int x[3][5];
Here
x
is a3 x 5
array ofint
s; more precisely,x
is an array of three element objects, each of which is an array of fiveint
s. In the expressionx[i]
, which is equivalent to(*((x)+(i)))
,x
is first converted to a pointer to the initial array of five ints. Theni
is adjusted according to the type ofx
, which conceptually entails multiplyingi
by the size of the object to which the pointer points, namely an array of five int objects. The results are added and indirection is applied to yield an array of five ints. When used in the expressionx[i][j]
, that array is in turn converted to a pointer to the first of theint
s, sox[i][j]
yields an int.这里x是一个3 x 5的整数数组;更准确地说,x是一个由三个元素对象组成的数组,每个元素对象是一个由五个整数组成的数组。在表达式x [i]中,它等价于(*((x)+(i))),x首先被转换为指向五个int的初始数组的指针。然后根据x的类型调整i,这在概念上需要将i乘以指针所指向的对象的大小,即五个int对象的数组。添加结果并应用间接以产生五个整数的数组。当在表达式x [i] [j]中使用时,该数组又转换为指向第一个int的指针,因此x [i] [j]产生一个int。
So we can say double myArray[5][7];
here myArray[3][2]
and myArray[0][0]
are not part of the same array.
所以我们可以说加倍myArray [5] [7];这里myArray [3] [2]和myArray [0] [0]不属于同一个数组。
Now that we are done here - let's get into something else:
现在我们已经完成了 - 让我们进入其他方面:
From standard §6.5.6.9
从标准§6.5.6.9
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements.
当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素;结果是两个数组元素的下标的差异。
But here myArray[3]
and myArray[0]
are denoting two different arrays. And that means myArrayp[3][2]
and myArray[0][0]
both belong to different arrays. And they are not one past the last element. So the behavior of the subtraction &myArray[3][2] - &myArray[0][0]
will not be defined by the standard.
但是这里myArray [3]和myArray [0]表示两个不同的数组。这意味着myArrayp [3] [2]和myArray [0] [0]都属于不同的数组。而且他们不是最后一个元素。因此,减法&myArray [3] [2] - &myArray [0] [0]的行为将不会被标准定义。
†Eric (Eric Postpischil) pointed out this idea.
†Eric(Eric Postpischil)指出了这个想法。
#2
0
In a row-major traversal, the declaration is array[height][width]
, and the usage is array[row][column]
. In row-major, stepping to the next number gives you the next column, unless you exceed the width and "wrap" to the next row. Each row adds width
to your index, and each column adds 1, making rows the "major" index.
在行主要遍历中,声明是array [height] [width],用法是array [row] [column]。在行专业中,步进到下一个数字会为您提供下一列,除非您超出宽度并“换行”到下一行。每行为索引添加宽度,每列添加1,使行成为“主要”索引。
In order to get the column-major equivalent, you assume the next value is the next row, and when the row exceeds the height, it "wraps" to the next column. This is described by index = column * height + row
.
为了得到列主要的等价物,你假设下一个值是下一行,当行超过高度时,它“包裹”到下一列。这由index = column * height + row描述。
So, for an array array[5][7]
of height 5, the index [3][2]
yields 2*5 + 3 = 13
.
因此,对于高度为5的数组数组[5] [7],索引[3] [2]产生2 * 5 + 3 = 13。
Let's verify with some code. You can get column-major behavior simply by switching the order of the indices.
让我们用一些代码验证。只需切换索引的顺序即可获得列主要行为。
#include <stdio.h>
int main() {
double array[7][5];
void *root = &array[0][0];
void *addr = &array[2][3];
size_t off = addr - root;
printf("memory offset: %d number offset: %d\n", off, off/sizeof(double));
return 0;
}
Running this program yields an address offset of 104, or 13 doubles.
运行此程序会产生104或13倍的地址偏移量。
EDIT: sorry for wrong answer
编辑:抱歉错误的答案
#3
0
The Simple Answer
C does not have multidimensional arrays, so we have to interpret double myArray[5][7]
as one-dimensional array of one-dimensional arrays. In double myArray[5][7]
, myArray
is an array of 5 elements. Each of those elements is an array of 7 double
.
C没有多维数组,因此我们必须将double myArray [5] [7]解释为一维数组的一维数组。在double myArray [5] [7]中,myArray是一个包含5个元素的数组。每个元素都是7个double的数组。
Thus, we can see that myArray[0][0]
and myArray[0][1]
are both members of myArray[0]
, and they are adjacent members. Thus, the elements proceed [0][0]
, [0][1]
, [0][2]
, and so on.
因此,我们可以看到myArray [0] [0]和myArray [0] [1]都是myArray [0]的成员,它们是相邻的成员。因此,元素继续[0] [0],[0] [1],[0] [2]等。
When we consider myArray[1]
, we see it comes after myArray[0]
. Since myArray[0]
is an array of 7 double
, myArray[1]
starts 7 double
after myArray[0]
.
当我们考虑myArray [1]时,我们看到它出现在myArray [0]之后。由于myArray [0]是一个7倍的数组,myArray [1]在myArray [0]之后启动7倍。
Now we can see that myArray[3][2]
is 3 arrays (of 7 double
) and 2 elements (of double
) after myArray[0][0]
. If a double
is 8 bytes, then this distance is 3•7•8 + 2•8 = 184 bytes.
现在我们可以看到myArray [0] [0]之后myArray [3] [2]是3个数组(7个双)和2个元素(double)。如果double是8个字节,则此距离为3•7•8 + 2•8 = 184个字节。
The Correct Answer
To my surprise, I cannot find text in the C standard that specifies that the size of an array of n elements equals n times the size of one element. Intuitively, it is “obvious”—until we consider that an implementation in an architecture without a flat address space might have some issues that require it to access arrays in complicated ways. Therefore, we do not know what the size of an array of 7 double
is, so we cannot calculate how far myArray[3][2]
is from myArray[0][0]
in general.
令我惊讶的是,我在C标准中找不到指定n个元素数组的大小等于一个元素大小的n倍的文本。直观地说,它是“显而易见的” - 直到我们认为没有平坦地址空间的架构中的实现可能会有一些问题需要它以复杂的方式访问数组。因此,我们不知道7 double的数组大小是多少,所以我们无法计算myArray [3] [2]与myArray [0] [0]的距离。
I do not know of any C implementations in which the size of an array of n elements is not n times the size of one element, so the calculation will work in all normal C implementations, but I do not see that it is necessarily so according to the C standard.
我不知道任何C实现,其中n个元素的数组的大小不是一个元素大小的n倍,因此计算将适用于所有正常的C实现,但我不认为它必须如此根据符合C标准。
Calculating the Distance in a Program
It has been suggested the address can be calculated using (char *) &myArray[3][2] - (char *) &myArray[0][0]
. Although this is not strictly conforming C, it will work in common C implementations. It works by converting the addresses to pointers to char
. Subtracting these two pointers then gives the distance between them in units of char
(which are bytes).
有人建议使用(char *)&myArray [3] [2] - (char *)和myArray [0] [0]计算地址。虽然这不是严格符合C,但它将适用于常见的C实现。它的工作原理是将地址转换为指向char的指针。减去这两个指针,然后以char为单位给出它们之间的距离(以字节为单位)。
Using uintptr_t
is another option, but I will omit discussion of it and its caveats as this answer is already too long.
使用uintptr_t是另一种选择,但我将省略对它的讨论及其警告,因为这个答案已经太长了。
A Wrong Way to Calculate Distance
One might think that &myArray[3][2]
is a pointer to double
and &myArray[0][0]
is a pointer to double
, so &myArray[3][2] - &myArray[0][0]
is the distance between them, measured in units of double
. However, the standard requires that pointers being subtracted must point to elements of the same array object or to one past the last element. (Also, for this purpose, an object can act as an array of one element.) However, myArray[3][2]
and myArray[0][0]
are not in the same array. myArray[3][2]
is in myArray[3]
, and myArray[0][0]
is in myArray[0]
. Further, neither of them is an element of myArray
, because its elements are arrays, but myArray[3][2]
and myArray[0][0]
are double
, not arrays.
有人可能认为&myArray [3] [2]是一个指向double的指针,而myArray [0] [0]是指向double的指针,所以&myArray [3] [2] - &myArray [0] [0]之间的距离是它们,以双倍为单位。但是,该标准要求被减去的指针必须指向同一个数组对象的元素或者指向最后一个元素的元素。 (另外,为此目的,一个对象可以作为一个元素的数组。)但是,myArray [3] [2]和myArray [0] [0]不在同一个数组中。 myArray [3] [2]在myArray [3]中,myArray [0] [0]在myArray [0]中。此外,它们都不是myArray的元素,因为它的元素是数组,但myArray [3] [2]和myArray [0] [0]是double,而不是数组。
Given this, one might ask how (char *) &myArray[3][2] - (char *) &myArray[0][0]
can be expected to work. Isn’t it also subtracting pointers to elements in different arrays? However, character types are special. The C standard says character pointers can be used to access the bytes that represent objects. (Technically, I do not see that the standard says these pointers can be subtracted—it only says that a pointer to an object can be converted to a pointer to a character type and then incremented successively to point to the remaining bytes of an object. However, I think the intent here is for character pointers to the bytes of an object to act as if the bytes of the object were an array.)
鉴于此,人们可能会问如何(char *)和myArray [3] [2] - (char *)和myArray [0] [0]可以工作。是不是也减去了指向不同数组中元素的指针?但是,字符类型很特殊。 C标准表示字符指针可用于访问表示对象的字节。 (从技术上讲,我没有看到标准说这些指针可以被减去 - 它只是说指向对象的指针可以转换为指向字符类型的指针,然后连续递增以指向对象的剩余字节。但是,我认为这里的意图是指向一个对象字节的字符指针,就像对象的字节是一个数组一样。)
#1
3
The memory lay out for the 2d array would be a contiguous chunk of memory.(Based on your question)
2d阵列的内存布局将是一块连续的内存。(基于你的问题)
int x[2][3] = {{0,1,2},{3,4,5}};
That will be layed out in (Your question)
这将在(你的问题)中列出
--+--+--+--+--+--+
0| 3| 1| 4|2 |5 |
--+--+--+--+--+--+
But in C
this is stored like
但在C中,这就像存储一样
--+--+--+--+--+--+
0| 1| 2| 3|4 |5 |
--+--+--+--+--+--+
Now you are absolutely right, that you can consider jumps between [0][0]
and [3][2]
but there is a better way to do that without thinking about all this, you can be sure that their offset will be their address differences.
现在你是绝对正确的,你可以考虑在[0] [0]和[3] [2]之间跳转但是有一个更好的方法来做到这一点而不考虑所有这些,你可以确定他们的偏移将是他们的解决差异。
You can simply get their addresses and subtract them.
您只需获取地址并减去它们即可。
ptrdiff_t ans = &a[3][2]-&a[0][0]
;(this is basically the gaps between the two elements)
ptrdiff_t ans =&a [3] [2] - &a [0] [0];(这基本上是两个元素之间的差距)
That yields the answer. printf("answer = %td",ans*sizeof(a[0][0]);
(One gap = sizeof(a[0][0])
) [In your case double
]
这就产生了答案。 printf(“answer =%td”,ans * sizeof(a [0] [0]);(一个间隙= sizeof(a [0] [0]))[在你的情况下为双]
Or even better way would be to
或者甚至更好的方式
ptrdiff_t ans = (char*)&a[3][2] - (char*)&a[0][0];//number of bytes between them.
I will explain a bit why char*
is important here:
我将解释一下为什么char *在这里很重要:
(this is not general enough)(char*)&a[0][0]
and
&a[0][0]
both contain the same thing
value-wise.
(char *)&a [0] [0]和&a [0] [0]都包含值相同的东西。 (这不够通用)
But it matters in pointer arithmetic. (Interpretation is different).
但它在指针算术中很重要。 (解释不同)。
When not using the cast, the interpretation is of the data type of array elements. That means now it consider the difference in double
s. When you cast it, it spits the result in or difference in char
-s.
不使用强制转换时,解释是数组元素的数据类型。这意味着现在考虑双打的差异。当你施放它时,它会将结果吐出或者不同于char-s。
And why this works? Because all data memory is byte
addressable and char
is of single bytes.
为什么这个有效?因为所有数据存储器都是字节可寻址的,而char是单字节的。
There is something more to this than expected , first let's see what is an array in C
? †
除此之外还有更多的东西,首先让我们看看C中的数组是什么? †
C does not really have multi-dimensional arrays. In C
it is realized as an array of arrays. And yes those multidimensional array elements are stored in row-major order.
C实际上没有多维数组。在C中,它被实现为数组阵列。是的,那些多维数组元素以行主顺序存储。
To clarify a bit more we can look into an example of standard §6.5.2.1
为了澄清一点,我们可以看一下标准§6.5.2.1的例子
Consider the array object defined by the declaration
考虑声明定义的数组对象
int x[3][5];
Here
x
is a3 x 5
array ofint
s; more precisely,x
is an array of three element objects, each of which is an array of fiveint
s. In the expressionx[i]
, which is equivalent to(*((x)+(i)))
,x
is first converted to a pointer to the initial array of five ints. Theni
is adjusted according to the type ofx
, which conceptually entails multiplyingi
by the size of the object to which the pointer points, namely an array of five int objects. The results are added and indirection is applied to yield an array of five ints. When used in the expressionx[i][j]
, that array is in turn converted to a pointer to the first of theint
s, sox[i][j]
yields an int.这里x是一个3 x 5的整数数组;更准确地说,x是一个由三个元素对象组成的数组,每个元素对象是一个由五个整数组成的数组。在表达式x [i]中,它等价于(*((x)+(i))),x首先被转换为指向五个int的初始数组的指针。然后根据x的类型调整i,这在概念上需要将i乘以指针所指向的对象的大小,即五个int对象的数组。添加结果并应用间接以产生五个整数的数组。当在表达式x [i] [j]中使用时,该数组又转换为指向第一个int的指针,因此x [i] [j]产生一个int。
So we can say double myArray[5][7];
here myArray[3][2]
and myArray[0][0]
are not part of the same array.
所以我们可以说加倍myArray [5] [7];这里myArray [3] [2]和myArray [0] [0]不属于同一个数组。
Now that we are done here - let's get into something else:
现在我们已经完成了 - 让我们进入其他方面:
From standard §6.5.6.9
从标准§6.5.6.9
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements.
当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素;结果是两个数组元素的下标的差异。
But here myArray[3]
and myArray[0]
are denoting two different arrays. And that means myArrayp[3][2]
and myArray[0][0]
both belong to different arrays. And they are not one past the last element. So the behavior of the subtraction &myArray[3][2] - &myArray[0][0]
will not be defined by the standard.
但是这里myArray [3]和myArray [0]表示两个不同的数组。这意味着myArrayp [3] [2]和myArray [0] [0]都属于不同的数组。而且他们不是最后一个元素。因此,减法&myArray [3] [2] - &myArray [0] [0]的行为将不会被标准定义。
†Eric (Eric Postpischil) pointed out this idea.
†Eric(Eric Postpischil)指出了这个想法。
#2
0
In a row-major traversal, the declaration is array[height][width]
, and the usage is array[row][column]
. In row-major, stepping to the next number gives you the next column, unless you exceed the width and "wrap" to the next row. Each row adds width
to your index, and each column adds 1, making rows the "major" index.
在行主要遍历中,声明是array [height] [width],用法是array [row] [column]。在行专业中,步进到下一个数字会为您提供下一列,除非您超出宽度并“换行”到下一行。每行为索引添加宽度,每列添加1,使行成为“主要”索引。
In order to get the column-major equivalent, you assume the next value is the next row, and when the row exceeds the height, it "wraps" to the next column. This is described by index = column * height + row
.
为了得到列主要的等价物,你假设下一个值是下一行,当行超过高度时,它“包裹”到下一列。这由index = column * height + row描述。
So, for an array array[5][7]
of height 5, the index [3][2]
yields 2*5 + 3 = 13
.
因此,对于高度为5的数组数组[5] [7],索引[3] [2]产生2 * 5 + 3 = 13。
Let's verify with some code. You can get column-major behavior simply by switching the order of the indices.
让我们用一些代码验证。只需切换索引的顺序即可获得列主要行为。
#include <stdio.h>
int main() {
double array[7][5];
void *root = &array[0][0];
void *addr = &array[2][3];
size_t off = addr - root;
printf("memory offset: %d number offset: %d\n", off, off/sizeof(double));
return 0;
}
Running this program yields an address offset of 104, or 13 doubles.
运行此程序会产生104或13倍的地址偏移量。
EDIT: sorry for wrong answer
编辑:抱歉错误的答案
#3
0
The Simple Answer
C does not have multidimensional arrays, so we have to interpret double myArray[5][7]
as one-dimensional array of one-dimensional arrays. In double myArray[5][7]
, myArray
is an array of 5 elements. Each of those elements is an array of 7 double
.
C没有多维数组,因此我们必须将double myArray [5] [7]解释为一维数组的一维数组。在double myArray [5] [7]中,myArray是一个包含5个元素的数组。每个元素都是7个double的数组。
Thus, we can see that myArray[0][0]
and myArray[0][1]
are both members of myArray[0]
, and they are adjacent members. Thus, the elements proceed [0][0]
, [0][1]
, [0][2]
, and so on.
因此,我们可以看到myArray [0] [0]和myArray [0] [1]都是myArray [0]的成员,它们是相邻的成员。因此,元素继续[0] [0],[0] [1],[0] [2]等。
When we consider myArray[1]
, we see it comes after myArray[0]
. Since myArray[0]
is an array of 7 double
, myArray[1]
starts 7 double
after myArray[0]
.
当我们考虑myArray [1]时,我们看到它出现在myArray [0]之后。由于myArray [0]是一个7倍的数组,myArray [1]在myArray [0]之后启动7倍。
Now we can see that myArray[3][2]
is 3 arrays (of 7 double
) and 2 elements (of double
) after myArray[0][0]
. If a double
is 8 bytes, then this distance is 3•7•8 + 2•8 = 184 bytes.
现在我们可以看到myArray [0] [0]之后myArray [3] [2]是3个数组(7个双)和2个元素(double)。如果double是8个字节,则此距离为3•7•8 + 2•8 = 184个字节。
The Correct Answer
To my surprise, I cannot find text in the C standard that specifies that the size of an array of n elements equals n times the size of one element. Intuitively, it is “obvious”—until we consider that an implementation in an architecture without a flat address space might have some issues that require it to access arrays in complicated ways. Therefore, we do not know what the size of an array of 7 double
is, so we cannot calculate how far myArray[3][2]
is from myArray[0][0]
in general.
令我惊讶的是,我在C标准中找不到指定n个元素数组的大小等于一个元素大小的n倍的文本。直观地说,它是“显而易见的” - 直到我们认为没有平坦地址空间的架构中的实现可能会有一些问题需要它以复杂的方式访问数组。因此,我们不知道7 double的数组大小是多少,所以我们无法计算myArray [3] [2]与myArray [0] [0]的距离。
I do not know of any C implementations in which the size of an array of n elements is not n times the size of one element, so the calculation will work in all normal C implementations, but I do not see that it is necessarily so according to the C standard.
我不知道任何C实现,其中n个元素的数组的大小不是一个元素大小的n倍,因此计算将适用于所有正常的C实现,但我不认为它必须如此根据符合C标准。
Calculating the Distance in a Program
It has been suggested the address can be calculated using (char *) &myArray[3][2] - (char *) &myArray[0][0]
. Although this is not strictly conforming C, it will work in common C implementations. It works by converting the addresses to pointers to char
. Subtracting these two pointers then gives the distance between them in units of char
(which are bytes).
有人建议使用(char *)&myArray [3] [2] - (char *)和myArray [0] [0]计算地址。虽然这不是严格符合C,但它将适用于常见的C实现。它的工作原理是将地址转换为指向char的指针。减去这两个指针,然后以char为单位给出它们之间的距离(以字节为单位)。
Using uintptr_t
is another option, but I will omit discussion of it and its caveats as this answer is already too long.
使用uintptr_t是另一种选择,但我将省略对它的讨论及其警告,因为这个答案已经太长了。
A Wrong Way to Calculate Distance
One might think that &myArray[3][2]
is a pointer to double
and &myArray[0][0]
is a pointer to double
, so &myArray[3][2] - &myArray[0][0]
is the distance between them, measured in units of double
. However, the standard requires that pointers being subtracted must point to elements of the same array object or to one past the last element. (Also, for this purpose, an object can act as an array of one element.) However, myArray[3][2]
and myArray[0][0]
are not in the same array. myArray[3][2]
is in myArray[3]
, and myArray[0][0]
is in myArray[0]
. Further, neither of them is an element of myArray
, because its elements are arrays, but myArray[3][2]
and myArray[0][0]
are double
, not arrays.
有人可能认为&myArray [3] [2]是一个指向double的指针,而myArray [0] [0]是指向double的指针,所以&myArray [3] [2] - &myArray [0] [0]之间的距离是它们,以双倍为单位。但是,该标准要求被减去的指针必须指向同一个数组对象的元素或者指向最后一个元素的元素。 (另外,为此目的,一个对象可以作为一个元素的数组。)但是,myArray [3] [2]和myArray [0] [0]不在同一个数组中。 myArray [3] [2]在myArray [3]中,myArray [0] [0]在myArray [0]中。此外,它们都不是myArray的元素,因为它的元素是数组,但myArray [3] [2]和myArray [0] [0]是double,而不是数组。
Given this, one might ask how (char *) &myArray[3][2] - (char *) &myArray[0][0]
can be expected to work. Isn’t it also subtracting pointers to elements in different arrays? However, character types are special. The C standard says character pointers can be used to access the bytes that represent objects. (Technically, I do not see that the standard says these pointers can be subtracted—it only says that a pointer to an object can be converted to a pointer to a character type and then incremented successively to point to the remaining bytes of an object. However, I think the intent here is for character pointers to the bytes of an object to act as if the bytes of the object were an array.)
鉴于此,人们可能会问如何(char *)和myArray [3] [2] - (char *)和myArray [0] [0]可以工作。是不是也减去了指向不同数组中元素的指针?但是,字符类型很特殊。 C标准表示字符指针可用于访问表示对象的字节。 (从技术上讲,我没有看到标准说这些指针可以被减去 - 它只是说指向对象的指针可以转换为指向字符类型的指针,然后连续递增以指向对象的剩余字节。但是,我认为这里的意图是指向一个对象字节的字符指针,就像对象的字节是一个数组一样。)