C的指针算术运算只限于两种形式:
一、指针加减整数
标准定义这种形式只能用于指向数组中某个元素的指针,如下图所示。
并且这类表达式的结果类型也是指针。这种形式也适用于使用malloc函数动态分配获得内存。
数组中的元素存储于连续的内存位置中,后面元素的地址大于前面元素的地址。通过上一次博客的分享,我们通过假设、进而计算求值,最终得出了指针加1就是使她指向数组中下一个元素,以此类推,加5使它向右移动5个元素的位置,减3则使它向左移动3个元素的位置。对整数进行扩展调整以保证对指针执行加法运算能产生这种结果,而不用管数组元素的长度如何。
调整思路:调整的权重为指针去掉一个*号,然后求sizeof。
附表:(指针运算结果)
表达式 | 假定p是个指向…的指针 | 而且*p的大小是… | 增加到指针的值 |
---|---|---|---|
p+1 | char | 1 | 1 |
p+1 | short | 2 | 2 |
p+1 | int | 4 | 4 |
p+1 | double | 8 | 8 |
p+2 | char | 1 | 2 |
p+2 | short | 2 | 4 |
p+2 | int | 4 | 8 |
p+2 | short | 8 | 16 |
注:对指针执行加法或减法运算之后如果结果指针所值的位置在数组第1个元素的前面或在数组最后一个元素的后面,那么其效果就是未定义的。让指针指向数组最后一个元素后面的那个位置是合法的,但对这个指针执行间接访问操作可能会失败。
应用举例:
float arr[5];
float *vp;
for( vp = &arr[0]; vp < &arr[5];)
{
*vp++ = 0;
}
这里有一个循环,把数组中所有元素都初始化为0。for语句的初始把vp指向数组的第1个元素。
这个例子中的指针运算是用++操作符完成的。增加值1与float的长度相乘,其结果加到指针vp上。经过第1次循环之后,指针在内存中的位置如下:
经过5次循环之后,vp就指向数组最后一个元素后面的那个内存位置。
此时循环终止。由于下标从0开始,所以具有5个元素的数组的最后一个元素的下标值为4。这样&arr[5]就表示数组最后一个元素后面那个内存位置的地址。当vp到达这个值时,我们就知道到达了数组的末尾,因而循环终止。
这个例子中的指针最后所指向的是数组最后一个元素后面的那个内存位置。指针可能可以合法地获得这个值,但对它执行间接访问时将可能意外地访问原先存储于这个位置的变量。我们一般无法知道那个位置原先存储的是什么变量。因而,在这种情况下,一般不允许对指向这个位置的指针执行间接访问操作。
二、指针加减指针
1.指针 - 指针
只有当两个指针都指向同一个数组中的元素时,才允许从一个指针减去连一个指针。两个指针相减的结果类型是ptrdiff_t,它是一种有符号整数类型。减法运算的值是两个指针在内存中的距离(该距离以数组元素的长度为单位,而不是以字节为单位),因为减法运算的结果将除以数组元素类型的长度。例如,如果p1指向arr[i],p[2]指向arr[j],那么p2 - p1的值就是j - i 的值。
注:这种对差值的调整使指针的运算结果与数据的类型无关。不论数组包含的元素类型如何,指针减法的值保持不变。值得注意的是,表达式p1 - p2仍然合法,它的值为-(j - i)。
2.指针 + 指针
由于指针加指针的值是一个相对于原数组地址相差较大的数值,该数值很有可能超越了我们所定义的数组的右边界,这样获得的地址值将是一个“盲值”,虽然它确实存在,但我们不能对这个地址做任何处理,因为我们无法得知这个位置原先存储的是什么变量。
今天的分享就到这里,希望我的分享能够帮助到你,快乐学习每一天!!!