Legal or out-of-bounds forming the address of the first element past the end? [closed]

半腔热情 提交于 2020-01-26 03:57:12

问题


In another question I saw &studmark[STUDNO][0] where STUDNO is the size of the array.

I wonder now if that code is already undefined behaviour. studmark[STUDNO] is one-past-the-end and while it may be created it must not be accessed. Is indexing that with [0] to then form the address valid? Or must one use simply studmark[STUDNO] which then degrades to a pointer one-past-the-end?

Arguments either way please with references to the standard.

Update: Sample code and output

#include <stdio.h>

#define STUDNO 16

int studmark[STUDNO][2];

int main() {
  printf("&studmark = %p\n", studmark);
  printf("&studmark[1][0] = %p\n", &studmark[1][0]);
  printf("&studmark[STUDNO-1][0] = %p\n", &studmark[STUDNO-1][0]);
  printf("&studmark[STUDNO][0] = %p\n", &studmark[STUDNO][0]);
  return 0;
}

Compiling gives no warnings and outputs:

./foo 
&studmark = 0x601060
&studmark[1][0] = 0x601068
&studmark[STUDNO-1][0] = 0x6010d8
&studmark[STUDNO][0] = 0x6010e0

回答1:


Given that the definition of studmark looks like this:

int studmark[STUDNO][2];

Then the expression &studmark[STUDNO][0] invokes undefined behavior.

To make the pointer dereferences more apparent, first we'll switch from array index notation from pointer notation. Section 6.5.2.1p2 of the C11 standard states:

The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))

So the above expression becomes:

&*(studmark[STUDNO] + 0)

Which becomes:

&*(*(studmark + STUDNO) + 0)

This expression starts with the & and * operators. When & preceedes * they cancel each other out. This spelled out in section 6.5.3.2p3:

The unary & operator yields the address of its operand. If the operand has type "type", the result has type "pointer to type". If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue.

So this can be reduced to:

*(studmark + STUDNO) + 0

Now we look at the addition. This is valid because creating a pointer to one element past the end of the array is legal as per section 6.5.6p8:

When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the ith element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+nth and i−nth elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. 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. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

This means studmark + STUDNO is a valid pointer, but it cannot be dereferenced. This is where the problem comes in. *(studmark + STUDNO) invokes undefined behavior because it dereferences one element past the end of the array.

So &studmark[STUDNO][0] is undefined behavior.

In contrast, this is valid:

&studmark[STUDNO]

As it is equal to:

&*(studmark + STUDNO)

And subsequently:

studmark + STUDNO

Because it creates a pointer to one element past the end of an array but does not dereference it.



来源:https://stackoverflow.com/questions/58858493/legal-or-out-of-bounds-forming-the-address-of-the-first-element-past-the-end

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!