开发者

Validity of the code

开发者 https://www.devze.com 2022-12-15 19:17 出处:网络
Consider the following code : void populate(int *arr) { for(int j=0;j<4;++j) arr[j]=0; } int main() { int array[2][2];

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 cod开发者_JAVA百科e 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?


Your array is two arrays of int[2], while your function populate() treats it as a single array of int[4]. Depending on exactly how the compiler decides to align the elements of array, this may not be a valid assumption.

Specifically, when j is 2 and you try to access arr[2], this is outside the bounds of main's array[0] and is therefore invalid.


You have an array of arrays. array[1] follows array[0] in memory, because arrays are contiguous. If p == array[0], then p[1] follows p[0], because arrays are contiguous. So, you are right: all the memory for array is contiguous.

In pictures, array looks like this.

+-----------------+-----------------+
|      [0]        |      [1]        |
+-----------------+-----------------+

Now, let's break down array[0] and array[1], they individually look like this:

+--------+--------+
|  [0]   |  [1]   |        
+--------+--------+

So, the final picture is:

+--------+--------+--------+--------+
| [0][0] | [0][1] | [1][0] | [1][1] |
+--------+--------+--------+--------+

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.


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.


In C everything is stored in linear memory segments. You are passing address of a[0][0] which would be same as address of a[0] so a[i][j] is same as a[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. then a[i][j] would be *(&a[i]+j).

0

精彩评论

暂无评论...
验证码 换一张
取 消