Pointers on C——6 Pointers.11

来源:互联网 发布:剑侠情缘手游数据互通 编辑:程序博客网 时间:2024/06/04 01:31

​6.11 Pointer Expressions

Now letʹs take a look at a variety of pointer expressions and see how they are evaluated when used both as R‐values and L‐values. Some of these expressions are commonly used, bat not all. The purpose of this exercise is not to give you aʺcookbookʺ of expressions but rather to build your skill in reading and writing them.First, letʹs set the stage with some declarations.

现在让我们观察各种不同的指针表达式,并看看当它们分别作为左值和右值时是如何进行求值的。有些表达式用得很普遍,但有些却不常用。这个练习的目的并不是想给你一本这类表达式的"烹调全书",而是想让你完善阅读和编写它们的技巧。首先,让我们来看一些声明。


char ch = 'a';

char *cp = &ch;

We now have two variables initialized like this:

现在,我们就有了两个变量,它们初始化如下:



The memory Location that follows ch is also shown because some of the expressions that we evaluate will access it, albeit erroneously. Because we donʹt know what its initial value is, a question mark is shown.Letʹs figure out an easy one first to get the ball rolling. The expression is:

图中还显示了ch 后面的那个内存位置,因为我们所求值的有些表达式将访问它(尽管是在错误情况下才会对它进行访问)。由于我们并不知道它的初始值,所以用一个问号来代替。首先来个简单的作为开始,如下面这个表达式


ch


When used as an R‐value, this expression has the value 'a' and is illustrated as:

当它作为右值使用时,表达式的值为'a' ,如下图所示:


The heavy oval indicates that the value in the variable ch is the value of the expression.But when this expression is used as an L‐value, it is the location that counts rather than the value that it contains, so it is illustrated differently:

那个粗椭圆提示变量ch 的值就是表达式的值。但是,当这个表达式作为左值使用时,它是这个内存的地址而不是该地址所包含的值,所以它的图示方式有所不同:



Here the location is marked with a heavy box, indicating that the location is the result.Additionally, its value is not shown because it isnʹt important; indeed, the value is about to be replaced by some new value. The remaining expressions are shown in a tabular form. Each table is followed by a description of the expressionʹs evaluation.

此时该位置用粗方框标记,提示这个位置就是表达式的结果。另外,它的值并未显示,因为它并不重要。事实上,这个值将被某个新值所取代。接下来的表达式将以表格的形式出现。每个表的后面是表达式求值过程的描述。



As an R‐value, this expressionʹs value is the address of the variable ch. Note that this value is the same as the value stored in the variable cp, but the expression doesnʹt mention cp so thatʹs not where the value conies from. Thus the oval is not around the arrow in cp. The second question is, why is this expression not a legal L‐value? The precedence table shows that the & operator produces an R‐value as a result, and they cannot be used as L‐values. But why? The answer is easy. When the expression &ch is evaluated, where is the result held in the computer? It must be somewhere, but you have no way of knowing where. The expression does not identify any specific location in the machineʹs memory, and thus it is not a legal L‐value.

作为右值,这个表达式的值是变量ch 的地址。注意这个值同变量cp 中所存储的值一样,但这个表达式并未提及cp ,所以这个结果值并不是因为它而产生的。这样,图中椭圆并不画于cp 的箭头周围。第2 个问题是,为什么这个表达式不是一个合法的左值?优先级表格显示&操作符的结果是个右值,它不能当作左值使用。但是为什么呢?答案很简单,当表达式&ch 进行求值时,它的结果应该存储于计算机的什么地方呢?它肯定会位于某个地方,但你无法知道它位于何处。这个表达式并未标识任何机器内存的特定位置,所以它不是一个合法的左值。


Youʹve seen this expression before. Its R‐value is the value in cp, as indicated. The Lvalue is the location cp. There is no indirection in this expression, so you do not follow the arrow.

你以前曾见到过这个表达式。它的右值如图所示就是cp 的值。它的左值就是cp 所处的内存位置。由于这个表达式并不进行间接访问操作,所以你不必依箭头所示进行间接访问。



This example is similar to &ch except that this time we take the address of the pointer variable. The type of this result is pointer to pointer to character. Once again, the value is stored in an unidentifiable location so the expression is not a legal L‐value.

这个例子与&ch 类似,不过我们这次所取的是指针变量的地址。这个结果的类型是指向字符的指针的指针。同样,这个值的存储位置并未清晰定义,所以这个表达式不是一个合法的左值。



Now we have added indirection so the results should come as no surprise. But the next few expressions begin to get more interesting.

现在我们加入了间接访问操作,所以它的结果应该不会令人惊奇。但接下来的几个表达式就比较有意思。



This diagram is more involved, so letʹs do it step by step. There are two operators here. * has a higher precedence than +, so the indirection is performed first (as shown by the solid arrow from cp to ch), which gets us its value (indicated by the dotted oval). A copy of this value is taken and added to one, giving the character 'b' as a result. The dotted lines show the movement of data as the expression is evaluated. The final result does not reside in any identifiable location, so this expression is not a legal L‐value. The precedence table confirms that the result of + is not an L‐value.

这个图涉及的东西更多,所以让我们一步一步来分析它。这里有两个操作符。*的优先级高于+,所以首先执行间接访问操作(如图中cp 到ch 的实线箭头所示),我们可以得到它的值(如虚线椭圆所示)。我们取得这个值的→份拷贝并把它与1 相加,表达式的最终结果为字符, b' 。图中虚线表示表达式求值时数据的移动过程。这个表达式的最终结果的存储位置并未清晰定义,所以它不是一个合法的左值。优先级表格证实+的结果不能作为左值。



In this example, weʹve added parentheses to the previous expression. The parentheses force the addition to go first, which adds one to a copy of the address in cp. The result so far is the pointer in the dotted oval. The indirection follows this arrow to the location just after ch, and the R‐value of the expression is the value in that location. The L‐value, of course, is the location itself.

在这个例子中,我们在前面那个表达式中增加了一个括号。这个括号使表达式先执行加法运算,就是把l 和cp 中所存储的地址相加。此时的结果值是图中虚线椭圆所示的指针。接下来的间接访问操作随着箭头访问紧随ch 之后的内存位置。这样,这个表达式的右值就是这个位置的值,而它的左

值是这个位置本身。


There is an important point to be learned here. Note that the result of the pointer addition is an R‐value because it does not reside in any identifiable location.Without the indirection, this expression would not be a legal L‐value. However, the indirection follows the pointer to a specific location. Thus, *(cp + 1) may be used as an L‐value even though cp + l may not. The indirection operator is one of only a few whose result is an L‐value.

在这里我们需要学习很重要的一点。注意指针加法运算的结果是个右值,因为它的存储位置并未清晰定义。如果没有间接访问操作,这个表达式将不是一个合法的左值。然而,间接访问跟随指针访问一个特定的位置。这样, *(Cp+1)就可以作用左值使用,尽管cp+1本身并不是左值。间接访

问操作符是少数几个其结果为左值的操作符之一。


But the expression is accessing the location after ch; how can we tell what resides there? In general, we canʹt, so expressions like this one are illegal. I discuss this topic in more depth later in this chapter.

但是,这个表达式所访问的是ch 后面的那个内存位置,我们如何知道原先存储于那个地方的是什么东西?一般而言,我们无法得知,所以像这样的表达式是非法的。本章的后面我将更为深入地探讨这个问题。



The ++ and -- operators are frequently used with pointer variables, so it is important to understand them in this context. In this expression, we increment the pointer variable cp. (To unclutter the diagrams, we no longer show the addition.) The result is a copy of the incremented pointer, because the prefix ++ increments before using the value in the surrounding expression. The copy is not stored in any identifiable location, so it is not a legal L‐value.

++和一操作符在指针变量中使用得相当频繁,所以在这种上下文环境中理解它们是非常重要的。在这个表达式中,我们增加了指针变量cp 的值。(为了让图更清楚,我们省略了加法)。表达式的结果是增值后的指针的一份拷贝,因为前缀++先增加它的操作数的值再返回这个结果。这份拷贝的存

储位置并未清晰定义,所以它不是一个合法的左值。



The postfix ++ produces the same value in cp, but it increments after the copy is made.Thus, the value of the expression is a copy of the original value of cp.Neither of the previous two expressions are legal L‐values. But they would be if we add indirection, as illustrated in the next two expressions.

后缀++操作符同样增加cp 的值,但它先返回cp 值的一份拷贝然后再增加cp 的值。这样,这个表达式的值就是cp 原来的值的一份拷贝。前面两个表达式的值都不是合法的左值。但如果我们在表达式中增加了间接访问操作符,它们就可以成为合法的左值,如下面的两个表达式所示。



Here, indirection is applied to the copy of the incremented pointer, so the R‐value is the value in the location following ch and the L‐value is that location.

这里,间接访问操作符作用于增值后的指针的拷贝上,所以它的右值是ch 后面那个内存地址的值,而它的左值就是那个位置本身。



Using the postfix ++ yields a different result: the R‐value and L‐value relate to the variable ch, which is where cp originally pointed. Again, the postfix operator uses the original value of its operand in the surrounding expression. The combination of indirection and the postfix ++ is often misunderstood. The precedence table indicates that the postfix ++ has a higher precedence than the *, yet it appears as it the indirection is being performed first. In fact, there are three steps involved: (1) ++makes a copy of cp, (2) the ++ increments cp, and finally, (3) the indirection is performed on the copy.

使用后缀++操作符所产生的结果不同:它的右值和左值分别是变量ch 的值和ch 的内存位置,也就是cp 原先所指。同样,后缀++ 操作符在周围的表达式中使用其原先操作数的值。间接访问操作符和后缀++操作符的组合常常令人误解。优先级表格显示后缀++ 操作符的优先级高于*操作符,但表达式的结果看上去像是先执行间接访问操作。事实上,这里涉及3 个步骤: (1) ++ 操作符产生cp 的一份拷贝, (2) 然后++ 操作符增加cp 的值, (3)最后,在cp 的拷贝上执行间接访问操作。


This expression is often used in loop to sequentially examine the contents of some array to which the pointer has previously been initialized. Some example are shown later in this chapter.

这个表达式常常在循环中出现,首先用一个数组的地址初始化指针,然后使用这种表达式就可以依次访问该数组的内容了。本章的后面显示了一些这方面的例子。


In this expression, the indirection is evaluated first due to the right‐to‐left associativity of these operators. Therefore, the location to which cp points is incremented; the result is a copy of the incremented value.

在这个表达式中,由于这两个操作符的结合性都是从右向左,所以首先执行的是间接访问操作。然后, cp 所指向的位置的值增加1,表达式的结果是这个增值后的值的一份拷贝。


The last three expressions are not used as often as some of the previous ones but deciphering them will increase your skill.

与前面一些表达式相比,最后3 个表达式在实际中使用得较少。但是,对它们有一个透彻的理解有助于提高你的技能。



With the postfix ++, we need parentheses to make the indirection go first. This expression is evaluated like the previous example except that the result is the value that ch had before the increment took place.

使用后缀++操作符,我们必须加上括号,使它首先执行间接访问操作。这个表达式的计算过程与前-个表达式相似,但它的结果值是ch 增值前的原先值。



This one looks pretty tricky, but it isnʹt really. There are three operators in this expression, which is what makes it look intimidating. If you analyze them one by one, though, each will be familiar. In fact, weʹve already evaluated *++cp earlier; all we are doing now is to increment its result. But letʹs start from scratch. Remember that the associativity of these operators is right to left, so the first thing that happens is ++cp;the dotted oval beneath cp illustrates the first intermediate result. Then we apply indirection to this copy, which takes us to the location after ch. The second intermediate result is shown with a dotted box because the next operator uses it as an L‐value. Finally, we apply ++ to this location, which increments its value. We display the value as ? + 1 because we do not know the original value of the location.

这个表达式看上去相当诡异,但事实上并不复杂。这个表达式共有3 个操作符,所以看上去有些吓人。但是,如果你逐个对它们进行分析,你会发现它们都很熟悉。事实上,我们先前已经计算了*++cp. 所以现在我们需要做的只是增加它的结果值。但是,让我们还是从头开始。记住这些操作符的结合性都是从右向左,所以首先执行的是++cp。 cp 下面的虚线椭圆表示第1 个中间结果。接着,我们对这个拷贝值进行间接访问,它使我们访问ch 后面的那个内存位置。第2 个中间结果用虚线方框表示,因为下一个操作符把它当作一个左值使用。最后,我们在这个位置执行++操作,也就是增加它的值。我们之所以把结果值显示为?+1 是因为我们并不知道这个位置原先的值。



The difference between this expression and the previous one is that the first ++ is postfix instead of prefix, so it is evaluated first because of its higher precedence. The indirection then takes us to cp instead of the following location.

这个表达式和前→个表达式的区别在于这次第1 个++操作符是后缀形式而不是前缀形式。由于它的优先级较高,所以先执行它。间接访问操作所访问的是cp 所指向的位置而不是cp 所指向位置后面的那个位置。


上一章 Pointers on C——6 Pointers.10