为什么C中不允许这个指针运算?
char arr[] = "Hello"; arr = arr + 1; // error occurs
据我所知,具有数组types的expression式被转换为指向数组的初始元素的指针types。 因此,我期望arr = arr + 1
(指向数组的第一个元素(arr)的指针变成指向数组的第二个元素的指针)。 为什么不在C中工作?
arr + 1
确实是指向数组的第二个元素的指针(即&arr[1]
)。
但是,这并不意味着你可以以某种方式将指针值写回到arr
。 至less有两个原因,你不能这样做。
首先, arr
是char
元素的数组 ,而不是指针。 这里有一个明显的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。
在大多数情况下都是如此。 在以下情况下不是这样:
-
使用addressof运算符(
&arr
)时。&arr
的types是char (*)[6]
。 这不是char**
。 -
使用
sizeof
运算符时。sizeof(arr)
是6
。 如果它是一个指针,它将是指针的大小(在最常见的平台中是4或8)。 -
用作赋值运算符的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 + 1
, arr
“衰减”到指向其第一个元素的指针,也就是说, arr == &arr[0]
。 所以arr + 1
是合法的指针运算,但是将它的值赋给arr
,这是一个数组,是非法的。