時に、以下のようなプログラム(プログラム自体は特に意味は無いです)を見かけます。

#include <stdio.h>
#include <stdlib.h>

int main(void){
    char *input = "1 5 9 2 6 4 8";
    int array[16];

    char *p = input;
    int i;
    for(i = 0; i < 16 && *p; ++i){
        array[i] = strtol(p, &p, 10);
    }
    for(int n = i, i = 0; i < n; ++i)
        printf("%d ", array[i]);
    return 0;
}

気になるのは、strtol(p, &p, 10) の部分です。

strtol のプロトタイプを見ると、

long strtol(
    const char * restrict nptr,
    char ** restrict endptr
    int base
);

のようになっていて、
第1引数と第2引数にrestrict修飾がされています。
私のざっくりとした理解ではそれは関数内でその引数を使う時に他の引数とかぶってはいけない(同じオブジェクト指すようなものであってはいけない)ということです。(つまり、私の理解では、制約違反。理解が間違っている場合そこら辺も解説して欲しいです。)
この場合、restrict制約に違反していることになるのでしょうか?

それとも型が違うのだから大丈夫?
型が違うから大丈夫なら、そもそも2つの引数にrestrict修飾する必要などないのでは?
逆に、このケースでrestrict制約違反になる場合とはどんな場合?

あと、
restrict制約に違反するようなプログラムを書いた場合、
それはすなわち動作未定義ですか?(例えば第一引数はconstでオブジェクトを変更しないことが明らかなので実質問題無いように思える)


(他に書く所がないのでここで)
コメントで、memcpy(p, p, 0) が動作未定義かどうか?
ということを書いたのですが、
規格のサンプルで、

void h(int n, int * restrict p, int * restrict q, int * restrict r)
{
    int i;
    for (i = 0; i < n; i++)
    p[i] = q[i] + r[i];
}

の場合、

h(100, a, b, b) has defined behavior, because array b is not modified within function h.

って書いてある。
(この場合第1引数と第2・3引数との制約で、第2と第3引数の間の制約ではないとも言える。)
理由として変更がされないからということであれば、
動作未定義かどうかは単にパラメータ(のポインタが同一オブジェクトを指すかどうか)だけでは(実装を知らない使用者側としては)判断ができずに、その実装によることになる。(実際には動作の説明が必要不可欠)
(逆に言えば、未定義動作(期待しないような動作)するような状況になったら、動作未定義だったのだなとわかるw)
だから、memcpy(p, p, 0)の場合も、明らかに変更するような動作が行われないので、defined behaviorだと言える。