在我正在阅读的一本书中,C++从零开始,在第113页,作者创建了一个字符数组:
然后他使用一个复制一些字符的函数:
1
| strcpy(myString,"Hello there"); |
然后他创建一个指向数组的指针:
然后他使用偏移量并在该偏移量处指定一个值:
我的问题是,p1是一个指针,所以它是一个内存地址,4的偏移量给了他前面的内存地址4个空格,这意味着他将字母"c"分配到内存地址,而不是存储在该地址的值。不应该是:
基本上,为什么*(p1+4)需要解引用,但p1[4]不需要解引用?
我试图理解这一点,唯一对我有意义的是,如果方括号充当星号来取消对指针的引用。这是正确的吗,还是有其他原因不需要取消对p1[4]的引用?
- 你为什么漏掉这些类型?请加上它们。
- 顺便说一句,那本书差不多二十年了。除非你对逆向计算感兴趣,否则你应该考虑从这十年中得到一个。
- []运算符返回引用。查一下它的含义和它在C++中的用法,我想你会没事的。
then he creates a pointer to the array:
假设,通过这个,您实际上是指使用声明和初始化p1;
那么你的解释就错了。p1是指向char的指针,而不是指向数组的指针。
在这个定义中,myString是char数组的(以前在您的问题中声明的)名称。在初始化过程中
名称myString转换为指针。该指针的值为&myString[0](即myString中第一个字符的地址)。这是p1将得到的值。
声明
然后将myString的第五个字符(因为索引是从零开始)设置为'c'。因此,结果是将myString[4]改为'c'的值。这意味着(myString的前11个字符)将是"Hellc there"。
假设上述情况,表达式*(p1[4])='c'将不会编译,因为(p1[4])是char类型,并且不能使用*运算符取消引用。
在语义上,在表达式p1[4]中等价于*(p1 + 4)。由于p1初始化为等于&myString[0],p1[4]也等于myString[4]和*(myString + 4)。
注:如果*(p1[4])='c'在您的代码中是有效的,那么p1[4] = 'c'将无效,这表明我关于p1的声明和初始化的假设是正确的,尽管您忽略了这些信息。
- 我知道:*(p1[4])不会编译,但我仍然认为您没有回答我的问题。我想说的是,p1是一个内存地址,所以如果你这样做,p1[4]=‘c’,你将到内存地址前面4个空格,并将字符‘c’分配给内存地址,而不是存储在该内存地址的值。
- 基本上,当你做*(p1+4)你需要去引用它,但当你做p1[4]你不需要去引用它?
- @阿米尼扎克,你误解了什么。*(p1 + 4)和p1[4]之间没有区别(如果p1是指针)。实际上,p1[4]被定义为*(p1 + 4)。
- p1[4]正在取消引用。它被指定为与*(p1 + 4)等效。
p1 + 4将是内存地址之外的4个位置。
表达式p1[4](完全等同于*(p1+4))称为左值表达式。我们说一个左值表达式指定了一个内存位置。或者换句话说,左值表达式是内存位置本身的同义词。您总是可以在左值表达式上使用操作符的&地址,这会给您一个指向内存位置的指针。
左值表达式将继续以三种可能的方式之一使用:
将值存储在指定的内存位置,或
从指定的内存位置检索值,或
两者都不是。
这三种情况没有特殊的语法来区分;相反,它取决于左值表达式所属的较大表达式。例如,应用&运算符的情况是3;出现在赋值运算符=的左侧的情况是1。大多数其他用法属于案例2。
p1[4]被视为*(p1 + 4),它是"从p1偏移4的值"。
另外,当您声明一个char数组时:
myString是指向数组的指针(它指向第一个元素)。所以当你做myString[4]时,它也被当作*(myString + 4)处理。
写*(p1[4])意味着*(*(p1 + 4))。
- myString不是指向数组的指针。它是数组的名称。当myString转换为指针(例如,当它被传递给strcpy()时)时,得到的指针等于myString的第一个元素的地址。
- "写*(p1[4])意味着*(*(p1+4))",这不是真的。指针的类型在这里起作用。
- 我觉得我的问题表达得很糟糕,但我问的基本上是你为什么要取消引用:*(p1+4)在那个地址分配一个值,但你不必取消引用p1[4]在那个地址分配一个值。