代码的有效性
考虑以下代码:
void populate(int *arr)
{
for(int j=0;j<4;++j)
arr[j]=0;
}
int main()
{
int array[2][2];
populate(&array[0][0]);
}
当地社区对此进行了讨论,无论该代码是否有效(我应该提及它的名称吗?)。一个人说它调用 UB 因为它违反了
C++ 标准 ($5.7/5 [expr.add])
“如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则求值不会产生溢出;否则,行为未定义< /强>。”
但我没有发现代码有任何问题,代码对我来说完全没问题。
所以,我只想知道这个代码是否有效?我错过了什么吗?
Consider the following code :
void populate(int *arr)
{
for(int j=0;j<4;++j)
arr[j]=0;
}
int main()
{
int array[2][2];
populate(&array[0][0]);
}
There was a discussion regarding this on a local community whether the code is valid or not(Am I supposed to mention its name?). One guy was saying that it invokes UB because it violates
C++ Standard ($5.7/5 [expr.add])
"If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined."
But I don't see anything wrong with the code,the code is perfectly OK for me.
So, I just want to know is this code valid or not? Am I missing something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您的
array
是两个int[2]
数组,而您的函数populate()
将其视为int[ 的单个数组4]
。根据编译器决定如何对齐数组元素的具体方式,这可能不是一个有效的假设。具体来说,当
j
为 2 并且您尝试访问arr[2]
时,这超出了main
的数组的范围[0]
因此无效。Your
array
is two arrays ofint[2]
, while your functionpopulate()
treats it as a single array ofint[4]
. Depending on exactly how the compiler decides to align the elements ofarray
, this may not be a valid assumption.Specifically, when
j
is 2 and you try to accessarr[2]
, this is outside the bounds ofmain
'sarray[0]
and is therefore invalid.你有一个数组的数组。在内存中,
array[1]
位于array[0]
后面,因为数组是连续的。如果p == array[0]
,则p[1]
位于p[0]
之后,因为数组是连续的。所以,你是对的:数组的所有内存都是连续的。在图片中,
array
看起来像这样。现在,让我们分解
array[0]
和array[1]
,它们分别看起来像这样:所以,最终的图片是:
现在的问题是,你能按照你现在的方式访问这个连续的内存。答案是,标准不保证。数组是连续的,但标准不允许按照您所做的方式进行索引。换句话说:
&array[0][0]+2 == &array[1][0]
,但是(&a[0][0] + 2 ) + 1
未定义,而&a[1][0] + 1
有效。如果这看起来很奇怪,那么确实如此,但是根据您从标准中发布的引用,您只允许计算数组内部或最多超出数组的指针(不取消引用“过去的”指针) 。实际上,我怀疑这会在任何地方失败,但至少根据标准,您的代码由于未定义的行为而无效。
请参阅这篇关于
comp.lang.c 的帖子
也是如此。You have an array of arrays.
array[1]
followsarray[0]
in memory, because arrays are contiguous. Ifp == array[0]
, thenp[1]
followsp[0]
, because arrays are contiguous. So, you are right: all the memory forarray
is contiguous.In pictures,
array
looks like this.Now, let's break down
array[0]
andarray[1]
, they individually look like this:So, the final picture is:
Now, the question is, can you access this contiguous memory the way you are. The answer is, it is not guaranteed by the standard. The arrays are contiguous, but the standard doesn't allow indexing the way you have done. In other words:
&array[0][0]+2 == &array[1][0]
, but(&a[0][0] + 2) + 1
is undefined whereas&a[1][0] + 1
is valid. If this seems strange, it is, but as per the quote you posted from the standard, you are only allowed to calculate a pointer that is either inside an array or at most one past the array (without dereferencing that "one past" pointer).In practice, I doubt that this would fail anywhere, but the according to the standard at least, your code is invalid because of undefined behavior.
See this post on
comp.lang.c
as well.但这并不总是有效。 C 有数组的数组,而不是二维数组。子数组并不总是指定为在内存中连续(静态数组可能是,检查 C/C++ 标准)在这个特定的示例中,我怀疑它工作正常。但是,如果您动态分配传入的内存,则很可能会失败,因为 malloc(或 new)可能已将子数组放置得很远。
但是,如果您想线性地遍历“2d”内存,则可以针对 1D 数组构造一个 2D 访问器,它将正常工作,并且像 memset 这样的东西将针对 1D 数组工作。
That is not going to always work. C has arrays of arrays, not 2D arrays. The sub-arrays are not always specified to be contiguous in memory(static arrays might be, check C/C++ standard) In this particular example, I suspect it works correctly. However, if you had dynamically allocated the memory being passed in, you quite possibly would fail, because malloc(or new) might have put the subarrays quite far apart.
If, however, you want to linearly walk down '2d' memory, you can construct a 2D accessor against a 1D array and it will work fine and things like memset will work against the 1D array.
在
C
中,所有内容都存储在线性内存段中。您正在传递a[0][0]
的地址,该地址与a[0]
的地址相同,因此a[i][j]
与a[i*ColSize+j]
相同,因为所有内容都是线性存储的。但是,如果动态分配内存,则会失败,因为那时所有行可能不会存储在连续位置。那么a[i][j]
将是*(&a[i]+j)
。In
C
everything is stored in linear memory segments. You are passing address ofa[0][0]
which would be same as address ofa[0]
soa[i][j]
is same asa[i*ColSize+j]
because everything is stored linearly. But if you allocate memory dynamically it would fail because that time all rows might not be stored in contiguous location. thena[i][j]
would be*(&a[i]+j)
.