You may sometimes use restrict-qualified pointers to access the same objects as other pointers, but only if the pointed-to objects are not modified. Here are C 2011 (N1570) 6.7.3.1 paragraphs 1-3 and the first part of paragraph 4 interspersed with how they apply to the code in the question.
6.7.3.1 Formal definition of restrict
1 Let D be a declaration of an ordinary identifier that provides a means of designating an object P as a restrict-qualified pointer to type T.
So int * restrict a
is such a declaration D. When max
is called with max(&num, &num);
, the object P is num
(or, more formally, the object named by num
), and T is int
. Similarly, int * restrict b
is another such declaration.
2 If D appears inside a block and does not have storage class extern, let B denote the block. If D appears in the list of parameter declarations of a function definition, let B denote the associated block. Otherwise, let B denote the block of main (or the block of whatever function is called at program startup in a freestanding environment).
These declarations appear in the parameter declarations of a function definition, so B is the block of the function definition, that is, the body of max
.
3 In what follows, a pointer expression E is said to be based on object P if (at some sequence point in the execution of B prior to the evaluation of E) modifying P to point to a copy of the array object into which it formerly pointed would change the value of E.137) Note that ‘‘based’’ is defined only for expressions with pointer types.
The function max
contains pointer expressions a
and b
, twice each, so these are each an instance of a pointer expression E. These expressions depend on the parameters a
and b
, respectively, because if we changed a
to point to a copy of num
instead of pointing to num
, then a
would have a different value (obviously), and similarly for b
. (Although num
is a scalar object, it acts like an array containing a single element for purposes of pointer arithmetic.)
4 During each execution of B, let L be any lvalue that has &L based on P. If L is used to access the value of the object X that it designates, and X is also modified (by any means), then the following requirements apply:…
During the execution of max
, the lvalue *a
has its address (&*a
, which is a
) based on P (a
), so the lvalue *a
is an instance of L. This lvalue is used to access num
, so num
is an instance of an object X. However num
is never modified during the execution of max
. Therefore, the requirements that follow do not apply. Similarly the lvalue *b
refers to an object (num
) that is never modified during the execution of max
.
Therefore, the code in max
does not violate the requirements for restrict
, and its behavior is defined by the C standard.