Cprogramming 简明教程

Pointer Arithmetics in C

C 中的 pointer 变量存储另一个变量的地址。地址始终是整数。那么,我们可以在指针上执行加法和减法等算数运算吗?在本章中,我们将解释哪些算数运算符在 C 中使用指针作为操作数,以及哪些运算没有定义可在指针上执行。

C pointers arithmetic operations 不同于一般的算术运算。以下是在 C 中的一些重要的指针算数运算:

  1. 指针的增量和减量

  2. 指针与整数的加减法

  3. Subtraction of Pointers

  4. Comparison of Pointers

让我们借助示例详细讨论所有这些指针算术运算。

Increment and Decrement of a Pointer

我们知道"++"和"--"用作 increment and decrement operators in C 。它们是一元运算符,以前缀或后缀方式与数字 variable 操作数一起使用,它们将变量的值增加或减少一。

假设在内存中地址为1000处创建了一个整数变量"x",其值为10。那么,"x++"会使"x"的值变为11。

int x = 10;   // created at address 1000

x++;          // x becomes 11

如果我们声明"y"为"x"的指针,并将"y"按1 (使用"y++")增加,会发生什么?假定"y"本身的地址为2000。

int x = 10;   // created at address 1000

// "y" is created at address 2000
// it holds 1000 (address of "x")
int *y = &x ;

y++;          // y becomes 1004

由于变量"y"存储1000("x"的地址),因此我们希望因"++"运算符而变为1001,但它却增加了4,这是"int"变量的大小。

之所以出现这种情况,是因为如果"x"的地址为1000,那么它将占据4个字节:1000、1001、1002和1003。因此,下一个整数只能放在1004中,不能放在它之前。因此,当"y"("x"的指针)增加时变为1004。

Example of Incrementing a Pointer

以下示例显示了如何增加一个指针的值 −

#include <stdio.h>

int main(){

   int x = 10;
   int *y = &x;

   printf("Value of y before increment: %d\n", y);

   y++;

   printf("Value of y after increment: %d", y);
}

运行代码并检查其输出:

Value of y before increment: 6422036
Value of y after increment: 6422040

可以看到,该值增加了4。同样,"--"运算符将值减小数据类型的字节数。

Example of Decrementing a Pointer

让我们将"x"和"y"的类型更改为"double"和"float",看看减号运算符的效果。

#include <stdio.h>

int main(){

   double x = 10;
   double *y = &x;

   printf("value of y before decrement: %ld\n", y);

   y--;

   printf("value of y after decrement: %ld", y);
}
Value of y before decrement: 6422032
Value of y after decrement: 6422024

声明一个 array 时,元素存储在相邻的内存位置中。在"int"数组的情况下,每个数组下标都相隔4个字节,如下图所示 −

memory locations

因此,如果一个变量存储数组第0个元素的地址,那么"增量"会将其移至第1个元素。

Example of Traversing an Array by Incrementing Pointer

以下示例显示了如何通过连续增加指针的值来遍历数组 −

#include <stdio.h>

int main(){

   int a[]= {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
   int len = sizeof(a)/sizeof(int);
   int *x = a;
   int i = 0;

   for(i = 0; i < len; i++){
      printf("Address of subscript %d = %d Value = %d\n", i, x, *x);
      x++;
   }

   return 0;
}

运行代码并检查其输出:

Address of subscript 0 = 6421984 Value = 10
Address of subscript 1 = 6421988 Value = 20
Address of subscript 2 = 6421992 Value = 30
Address of subscript 3 = 6421996 Value = 40
Address of subscript 4 = 6422000 Value = 50
Address of subscript 5 = 6422004 Value = 60
Address of subscript 6 = 6422008 Value = 70
Address of subscript 7 = 6422012 Value = 80
Address of subscript 8 = 6422016 Value = 90
Address of subscript 9 = 6422020 Value = 100

Addition and Subtraction of Integer to Pointer

可以对指针进行整数加减运算。当将一个整数添加到指针时,指针将指向下一个内存地址。同样,当从指针中减去一个整数时,指针将指向前一个内存位置。

将一个整数加减到指针中不会将该值加减到指针中,而是将与数据类型的大小相乘的值加减到指针中。

例如,有一个整数指针变量ptr,它指向地址123400,如果向ptr添加1 (ptr+1),它将指向地址123404(整数的大小为4)。

让我们计算一下,

ptr = 123400
ptr = ptr + 1
ptr = ptr + sizeof(int)*1
ptr = 123400 + 4
ptr = 123404

Example of Adding Value to a Pointer

在以下示例中,我们正在声明一个数组和 pointer to an array 。使用数组的第一个元素初始化指针,然后向指针中添加一个整数值(2)以获得数组的第三个元素。

#include <stdio.h>

int main() {
  int int_arr[] = {12, 23, 45, 67, 89};
  int *ptrArr = int_arr;

  printf("Value at ptrArr: %d\n", *ptrArr);

  // Adding 2 in ptrArr
  ptrArr = ptrArr + 2;

  printf("Value at ptrArr after adding 2: %d\n", *ptrArr);

  return 0;
}
Value at ptrArr: 12
Value at ptrArr after adding 2: 45

Example of Subtracting Value to a Pointer

在以下示例中,我们声明了一个数组和一个指向数组的指针。用数组的最后一个元素初始化指针,然后从指针中减去一个整数值 (2) 以获取数组的第三个元素。

#include <stdio.h>

int main() {
  int int_arr[] = {12, 23, 45, 67, 89};
  int *ptrArr = &int_arr[4]; // points to last element

  printf("Value at ptrArr: %d\n", *ptrArr);

  // Subtracting 2 in ptrArr
  ptrArr = ptrArr - 2;

  printf("Value at ptrArr after adding 2: %d\n", *ptrArr);

  return 0;
}
Value at ptrArr: 89
Value at ptrArr after adding 2: 45

Subtraction of Pointers

+"−" 运算符与常规数字操作数一起使用时,我们很熟悉它们。但是,当您将这些运算符与指针一起使用时,它们的行为会稍有不同。

由于指针是相当大的整数(尤其是在现代 64 位系统中),因此两个指针的加法是毫无意义的。当我们向指针添加 1,它指向可能存储整数的下一个位置。显然,当我们添加一个指针(本身是一个大整数)时,它指向的位置可能不在内存布局中。

但是,两个指针的减法是切合实际的。它返回可以放入两个指针中的数据类型的数量。

Example of Subtracting Two Pointers

让我们取前面示例中的数组,并对 a[0] 和 a[9] 的指针执行减法

#include <stdio.h>

int main(){

   int a[]= {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
   int *x = &a[0]; // zeroth element
   int *y = &a[9]; // last element

   printf("Add of a[0]: %ld add of a[9]: %ld\n", x, y);
   printf("Subtraction of two pointers: %ld", y-x);

}

运行代码并检查其输出:

Add of a[0]: 140729162482768 add of a[9]: 140729162482804
Subtraction of two pointers: 9

可以看到两个整数之间的数值差为 36;它表明减法为 9,因为它可以在两个指针之间容纳 9 个整数。

Comparison of Pointers

指针可以使用 relational operators (例如 "==", "<" 和 ">") 进行比较。如果 "p1" 和 "p2" 指向彼此相关的变量(例如同一数组的元素),那么可以对 "p1" 和 "p2" 进行有意义的比较。

Example of Comparing Pointers

在以下示例中,我们声明了两个指针,并分别用数组的第一个元素和最后一个元素对它们进行初始化。只要它指向的地址小于或等于最后一个数组元素的地址 &var[MAX − 1] (即第二个指针),我们将继续递增第一个变量指针。

#include <stdio.h>

const int MAX = 3;

int main() {
  int var[] = {10, 100, 200};
  int i, *ptr1, *ptr2;

  // Initializing pointers
  ptr1 = var;
  ptr2 = &var[MAX - 1];

  while (ptr1 <= ptr2) {
    printf("Address of var[%d] = %p\n", i, ptr1);
    printf("Value of var[%d] = %d\n", i, *ptr1);

    /* point to the previous location */
    ptr1++;
    i++;
  }

  return 0;
}

运行代码并检查其输出:

Address of var[0] = 0x7ffe7101498c
Value of var[0] = 10
Address of var[1] = 0x7ffe71014990
Value of var[1] = 100
Address of var[2] = 0x7ffe71014994
Value of var[2] = 200