为什么C中不允许这个指针运算?

char arr[] = "Hello"; arr = arr + 1; // error occurs 

据我所知,具有数组types的expression式被转换为指向数组的初始元素的指针types。 因此,我期望arr = arr + 1 (指向数组的第一个元素(arr)的指针变成指向数组的第二个元素的指针)。 为什么不在C中工作?

arr + 1确实是指向数组的第二个元素的指针(即&arr[1] )。

但是,这并不意味着你可以以某种方式将指针值写回到arr 。 至less有两个原因,你不能这样做。

首先, arrchar元素的数组 ,而不是指针。 这里有一个明显的types不匹配。

其次,作为一个数组, arr是一个不可修改的左值。 你不能改变arr本身,你只能改变它的元素 (这个区别有些难以理解,但它是存在的)。

最后,如果我们忽略更深层次的复杂性并关注顶层正式发生的事情,由于数组types的衰减,您的expression式相当于

 (char *) arr = (char *) arr + 1; 

由于左侧是[隐式]types转换的结果,赋值是不可能的。 在Ctypes转换总是产生rvalues。 你不能分配给右值。

换句话说,这不是在这里不允许的“指针算术”。 指针算术很好。 这是你的指针算术的结果,导致错误。

数组是不可修改的左值。 它们不能是赋值运算符的左操作数。

C11-§6.3.2.1:

一个可修改的左值是没有数组types的左值,没有不完整的types,[…]

§6.5.16/ 2:

赋值运算符的左操作数应该有一个可修改的左值。

在声明中

 arr = arr + 1; 

arr=运算符的左操作数,是数组types。 它不能被修改。
所以,这不是指针运算,而是赋值运算符上语言的约束,是语法错误的原因。


请注意,在某些情况下,数组衰减到指向其第一个元素的指针,尽pipe指针和数组是不同的types。 数组不是指针 。 只有指针算术和数组索引是等价的。 例如

 char *ptr = &arr[0] + 1 => &(*(arr + 0)) + 1 => &(*arr) + 1 => arr + 1 // * and & nullify each other 

这是因为数组与指针类似,只是它们不能被修改。 但是,您可以修改指向数组的指针。 对于上面的例子,你可以这样做:

 char arr[]="Hello"; char *ptr=arr; ptr=ptr+1; 

最初,指针ptr将指向数组的第一个字符,即'H' ,修改该值后,它将指向第二个字符,即'e' 。 您还可以执行以下操作:

 char arr[]="Hello"; char *ptr=arr; ptr=arr+1; 

两者都产生相同的效果,这表明arr+1确实是指针运算。 但是你不能修改arr的值,因为它的types是字符数组的types而不是指向字符数组的指针。

据我所知,具有数组types的expression式被转换为指向数组的初始元素的指针types。

在大多数情况下都是如此。 在以下情况下不是这样:

  1. 使用addressof运算符( &arr )时。 &arr的types是char (*)[6] 。 这不是char**

  2. 使用sizeof运算符时。 sizeof(arr)6 。 如果它是一个指针,它将是指针的大小(在最常见的平台中是4或8)。

  3. 用作赋值运算符的LHS时。 数组types的variables是不可修改的。

因此,我期望arr = arr + 1 (指向数组的第一个元素(arr)的指针变成指向数组的第二个元素的指针)。 为什么不用C来做这项工作?

expression式的RHS评估为指向arr的第二个元素的指针。 但是,由于上述(3),该行不起作用。 arr不是可修改的值。 它不能用作赋值操作符的LHS。

char[]不是指针,而char*是一个指针。 这工作,但它是错误的解决scheme:

 int main() { char *arr = "Hello"; arr = arr + 1; // Wrong! printf("%s\n", arr); // Output: ello } 

如果arr是用malloc堆分配的,你可以得到内存泄漏,如果free内存启动arr+1不是arr

但是你可以做这样的事情:

 int main() { char arr[] = "Hello"; char *wordFromSecondLetter = &arr[0] + 1; printf("%s\n", wordFromSecondLetter); // Output: ello } 

或者像这样

 int main() { char arr[] = "Hello"; printf("%s\n", &arr[1]); // Output: ello } 

因为arr不是一个指针而是一个char数组。 你可以通过检查sizeof arr来validation。 为了得到一个char指针,你应该使用char *arr = "Hello";

指针和数组之间最大的区别就是你可以直接给一个指针赋值,但是你不能这样做。

实际上,当你写arr + 1arr “衰减”到指向其第一个元素的指针,也就是说, arr == &arr[0] 。 所以arr + 1是合法的指针运算,但是将它的值赋给arr ,这是一个数组,是非法的。