Pointers on C——6 Pointers.13

来源:互联网 发布:淘宝网代卖怎么做的 编辑:程序博客网 时间:2024/06/18 08:36

​6.13.1 Arithmetic Operations

Pointer arithmetic in C is restricted to exactly two forms. The first form is:

pointer ± integer

This form is defined by the Standard only for pointers that are pointing at an element of an array, such as this one,

标准定义这种形式只能用于指向数组中某个元素的指针,如下图所示。


and yields a result of the same type as the pointer. This form also works with dynamically allocated memory obtained from malloc (see Chapter 11), though through an oversight the Standard fails to mention this fact.

并且这类表达式的结果类型也是指针。这种形式也适用于使用malloc 函数动态分配获得的内存(见第11 章),尽管翻遍标准也未见它提及这个事实。

 

Elements in an array are stored in consecutive memory locations, and the later elements have larger addresses than the earlier ones. Given this information, it is easy to see that adding one to the pointer moves it to the next element in the array, adding five moves it five elements to the right, and so forth. Subtracting three moves it three elements to the left. Scaling the integer ensures that the addition produces this result no matter what size elements are in the array.

数组中的元素存储于连续的内存位置中,后面元素的地址大于前面元素的地址。因此,我们很容易看出,对一个指针加l 使它指向数组中下一个元素,加5 使它向右移动5 个元素的位置,依次类推。把一个指针减去3 使它向左移动3 个元素的位置。对整数进行扩展保证对指针执行加法运算能产生这种结果,而不管数组元素的长度如何。


The effect of an addition or a subtraction is undefined if the result points to anything earlier than the first element of the array or if it points to any element more than one beyond the last element of the array. It is legal for the pointer to go one element past the end of the array, but indirection may not be performed on it then.

对指针执行加法或减法运算之后如果结果指针所指的位置在数组第1 个元素的前面或在数组最后一个元素的后面,那么其效果就是未定义的。让指针指向数组最后一个元素后面的那个位置是合法的,但对这个指针执行间接访问可能会失败。


Time for an example. Here is a loop that initializes all of the elements of an array to zero. (Chapter 8 discusses the efficiency of loops like this one compared to loops that use subscripts.)

是该举个例子的时候了。这里有一个循环,把数组中所有的元素都初始化为零。(第8 章将讨论类似这种循环和使用下标访问的循环之间的效率比较)。


#define N_VALUES 5

float values[N_VALUES];

float *vp;

for( vp = &values[0]; vp < &values[N_VALUES]; )

*vp++ = 0;

The initialization step of the for statement makes vp point to the first element of the array.

for 语旬的初始部分把vp 指向数组的第1 个元素。


The pointer arithmetic in this example is performed by the ++ operator. The increment value, one, is multiplied by the size of a float, and this value is added to the pointer vp. After the first time through the body of the loop, memory looks like this:

这个例子中的指针运算是用++操作符完成的。增加值1 与float 的长度相乘,其结果加到指针vp 上。经过第1 次循环之后,指针在内存中的位置如下:


After five times through the loop, vp has gone past the end of the array

经过5 次循环之后, vp 就指向数组最后一个元素后面的那个内存位置。


and the loop stops. With subscript values beginning at zero, the last element of an array of five elements will have a subscript of four. Thus &value[N_VALUES] represents the address of the first location beyond the right end of the array. When vp reaches this value, we know we have reached the end of the array, and the loop terminates.

此时循环终止。由于下标值从零开始,所以具有5 个元素的数组的最后一个元素的下标值为4 。这样, &values [N_VALUES] 表示数组最后一个元素后面那个内存位置的地址。当vp到达这个值时,我们就知道到达了数组的末尾,故循环终止。


The pointer in this example goes one element beyond the end of the array. The pointer may legally attain this value but applying indirection to it will access whatever other variable (if any) happens to reside in that location. The programmer generally has no way of determining what variable that might be, which is why indirection is not allowed in this circumstance.

这个例子中的指针最后所指向的是数组最后一个元素后面的那个内存位置。指针可能可以合法地获得这个值,但对它执行间接访问时将可能意外地访问原先存储于这个位置的变量。程序员一般无法知道那个位置原先存储的是什么变量。因此,在这种情况下,一般不允许对指向这个位置的指

针执行间接访问操作。


The second type of pointer arithmetic has the form:

pointer - pointer


Subtracting one pointer from another is allowed only when both point to elements of the same array, like this:

只有当两个指针都指向同一个数组中的元素时,才允许从一个指针减去另一个指针,如下所示:

The result of subtracting two pointers is of type ptrdiff_t, which will be a signed integral type. The value is the distance (measured in array elements, not bytes) between the two pointers, because the result of the subtraction is divided (scaled) by the size of the array elements. For example, if p1 points to array[i] and p2 points to array[j] then p2 – p1 will have the same value as j – i.

两个指针相减的结果的类型是ptrdiff_t ,它是一种有符号整数类型。减法运算的值是两个指针在内存中的距离(以数组元素的长度为单位,而不是以字节为单位),因为减法运算的结果将除以数组元素类型的长度。例如,如果p1 指向array[i] 而p2 指向array [j] ,那么p2-p1 的值就是j-i 的值。


Letʹs see how this works with a specific type. Suppose the array in the previous diagram consisted of floats occupying four bytes each. If the array began at location 1000, then p1 would contain 1004 and p2 would contain 1024. The result of the expression p2 – p1 would be five, though, because the difference between the pointer values (20) is divided by the size of each element (4).

让我们看一下它是如何作用于某个特定类型的。假定前图中数组元素的类型为float ,每个元素占据4 个字节的内存空间。如果数组的起始位置为1000 , p1 的值是1004 , p2 的值是1024 ,但表达式p2-p1 的结果值将是5 ,因为两个指针的差值(20) 将除以每个元素的长度(4) 。


Once again, scaling makes the result independent of the dataʹs type. The result of this pointer subtraction will be five no matter what type of data the array contains.

同样,这种对差值的调整使指针的运算结果与数据的类型无关。不论数组包含的元素类型如何,这个指针减法运算的值总是5。


Is the expression p1 - p2 legal? Yes, if both pointers are pointing to elements of the same array. In the previous example, its value would be –5.

那么,表达式p1-p2 是否合法呢?是的,如果两个指针都指向同一个数组中的元素,这个表达式就是合法的。在前一个例子中,这个值将是-5 。


The result of subtracting two pointers that do not point to the same array is undefined for the same reason that subtracting the addresses of two houses on different streets doesnʹt tell you the number of houses in between them. The programmer has no way of knowing where the two arrays might have been allocated relative to one another. Without this knowledge, the distance from one pointer to another has no meaning.

如果两个指针所指向的不是同一个数组中的元素,那么它们之间相减的结果是未定义的。就像如果你把两个位于不同街道的房子的门牌号码相减不可能获得这两所房子间的房子数一样。程序员无从知道两个数组在内存中的相对位置,如果不知道这一点,两个指针之间的距离就毫无意义。


In practice, most compilers do not check whether the result of a pointer expression falls within any legal bounds. Therefore, it is up to the programmer to make sure it does. Similarly, the compiler will not prevent you from taking the address of a scalar variable and performing pointer arithmetic on it, even though there is no way to predict what variable the result will point to. Out‐of‐range pointers and pointer to unknown values are two common causes of errors. When using pointer arithmetic, be very careful that the result points to something meaningful.

实际上,绝大多数编译器都不会检查指针表达式的结果是否位于合法的边界之内。因此,程序员应该负起责任,确保这一点。类似,编译器将不会阻止你取一个标量变量的地址并对它执行指针运算,即使它无法预测运算结果所产生的指针将指向哪个变量。越界指针和指向未知值的指针是两个常见的错误根源。当你使用指针运算时,必须非常小心,确信运算的结果将指向有意义的东西。


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