int *shiftRmemmove(int *arr, size_t size)
{
if(arr && size)
{
memmove(arr + size - 1, arr + size - 2, (size - 1) *sizeof(*arr));
arr[0] = 0;
}
return arr;
}
是否定义为size == 1
?它正在计算并传递对第一个元素之前的数组元素的引用。它相当于:memove(arr, arr -1, 0);
(©Jabberwocky)
如果
arr
是指向数组第一个元素的指针,并且如果size
是 1,则即使尝试形成地址arr + size - 2
也是未定义的行为。C 标准(C23 标准草案 6.5.6 9)对此进行了详细说明:正如C 标准ch中提到的。7.24.1 第 2 款(适用于
<string.h>
- 强调我的所有功能):所以您正在拨打电话:
其中第二个(指针)参数没有有效值。该标准明确禁止您形成此类指针,因为第 7.1.4 章(由第一个引用指出)提到:
结论:标准明确禁止这样做。该行为是未定义的。
arr
是一个指针,但是,从注释来看,我们打算假设它指向某个 array 的元素 0A
。考虑这个表达式
arr + size - 2
。arr + size
是没有争议的;它指向&A[1]
,即使A
是一个只有 1 个元素的数组,因此它&A[1]
是“刚好超出”数组最后一个元素的地址。对于
arr + size - 2
,实际上&A[1] - 2
,我们考虑 C 2018 6.5.6 8:这段话没有定义结果,
&A[1] - 2
因为索引为 -1 的数组元素A
不存在。仅此一点就足以使行为未定义,因为标准中没有其他内容定义它,并且 C 2018 4 2 告诉我们“本文档中以其他方式指示未定义的行为......通过省略任何明确的行为定义。” 然而,6.5.6 8 继续:这里,指针操作数 (
&A[1]
) 和结果 (&(A[-1]
) 不指向同一数组对象的元素或它后面的元素,因此行为未定义。的求值
arr + size - 2
发生在memmove
调用之前,因此是否memmove
使用其对应的参数无关紧要;该行为已经是未定义的。