C 语言编程教程

C 语言 - 首页

C 语言基础

C 语言 - 概述 C 语言 - 特性 C 语言 - 发展历史 C 语言 - 环境设置 C 语言 - 程序结构 C 语言 - Hello World C - 编译过程 C - 注释 C - 标记 C - 关键字 C - 标识符 C - 用户输入 C - 基本语法 C - 数据类型 C - 变量 C - 整数提升 C - 类型转换 C - 类型转换 C - 布尔值

C 语言中的常量和文字

C - 常量 C - 字面量 C - 转义序列 C - 格式说明符

C 语言中的运算符

C - 运算符 C - 算术运算符 C - 关系运算符 C - 逻辑运算符 C - 位运算符 C - 赋值运算符 C - 一元运算符 C - 递增和递减运算符 C - 三元运算符 C - sizeof 运算符 C - 运算符优先级 C - 其他运算符

C 语言中的决策

C - 决策 C - if 语句 C - if...else 语句 C - 嵌套 if 语句 C - switch 语句 C - 嵌套 switch 语句

C 语言中的循环

C - 循环 C - While 循环 C - For 循环 C - Do...while 循环 C - 嵌套循环 C - 无限循环 C - Break 语句 C - Continue 语句 C - goto 语句

C 语言中的函数

C - 函数 C - Main 函数 C - 按值调用函数 C - 按引用调用函数 C - 嵌套函数 C - 可变参数函数 C - 用户定义函数 C - 回调函数 C - return 语句 C - 递归

C 语言中的作用域规则

C - 作用域规则 C - 静态变量 C - 全局变量

C 语言中的数组

C - 数组 C - 数组的属性 C - 多维数组 C - 将数组传递给函数 C - 从函数返回数组 C - 可变长度数组

C 语言中的指针

C - 指针 C - 指针和数组 C - 指针的应用 C - 指针运算 C - 指针数组 C - 指向指针的指针 C - 将指针传递给函数 C - 从函数返回指针 C - 函数指针 C - 指向数组的指针 C - 指向结构体的指针 C - 指针链 C - 指针 vs 数组 C - 字符指针和函数 C - NULL 指针 C - void 指针 C - 悬垂指针 C - 解引用指针 C - Near、Far 和 Huge 指针 C - 指针数组的初始化 C - 指针与多维数组

C 语言中的字符串

C - 字符串 C - 字符串数组 C - 特殊字符

C 语言的结构体和联合

C - 结构体 C - 结构体和函数 C - 结构体数组 C - 自引用结构 C - 查找表 C - 点 (.) 运算符 C - 枚举(或 enum) C - 结构填充和打包 C - 嵌套结构 C - 匿名结构和联合 C - 联合 C - Bit 位字段 C - Typedef

C 语言中的文件处理

C - 输入和输出 C - 文件 I/O(文件处理)

C 语言中的预处理器

C - 预处理器 C - #pragma 编译指示 C - 预处理器操作符 C - 宏 C - 头文件

C 语言中的内存管理

C - 内存管理 C - 内存地址 C - 存储类

C 其他主题

C - 错误处理 C - 可变参数 C - 命令执行 C - 数学函数 C - static 静态关键字 C - 随机数生成 C - 命令行参数

C 语言编程资源

C语言问题与解答答案 C语言快速指南 C语言速查表 C语言实用资源 C语言讨论


C 语言中的指针运算

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

C 语言指针算术运算与一般的算术运算不同。以下是 C 语言中一些重要的指针算术运算:

  • 指针的递增和递减
  • 指针对整数的加减
  • 指针的减法
  • 指针的比较

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

指针的递增和递减

我们知道,在 C 语言中,"++"和"--"分别用作递增和递减运算符。它们是一元运算符,以前缀或后缀方式与数值型变量操作数一起使用,它们将变量的值加一或减一。

假设在内存地址 1000 处创建一个整型变量"x",其值为 10。然后,执行"x++"操作将"x"的值改为 11。

int x = 10; // 在地址 1000 处创建

x++; // x 变为 11

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

int x = 10; // 在地址1000处创建

// "y"在地址2000处创建
// 它保存的是1000("x"的地址)
int *y = &x;

y++; // y 变为 1004

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

这是因为,如果"x"的地址是 1000,那么它占用 4 个字节:1000、1001、1002 和 1003。因此,下一个整数只能放在 1004 中,而不能放在它之前。因此,"y"(指向"x"的指针)在增加后变为 1004。

指针增加示例

以下示例展示了如何增加指针 -

#include <stdio.h>

int main(){

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

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

   y++;

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

输出

运行代码并检查其输出 −

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

您可以看到值增加了 4。同样,"--"运算符将值按数据类型的大小递减。

指针递减示例

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

#include <stdio.h>

int main(){

   double x = 10;
   double *y = &x;
   
   printf("value of y before decrement: %ld
", y);
   
   y--;
   
   printf("value of y after decrement: %ld", y);
}

输出

Value of y before decrement: 6422032
Value of y after decrement: 6422024

声明数组时,元素存储在相邻的内存位置。对于"int"数组,每个数组下标相隔 4 个字节,如下图所示 -

内存位置

因此,如果一个变量存储的是数组第 0 个元素的地址,则"increment"操作会将其移至第 1 个元素。

通过递增指针遍历数组的示例

以下示例展示了如何通过连续递增指针来遍历数组 -

#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
", 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

指针与整数的加减运算

指针可以与整数相加或相减。当将整数与指针相加时,指针指向下一个内存地址。类似地,当从指针中减去一个整数时,指针指向先前的内存位置。

对指针进行整数加减运算不会将整数值加到指针上或减去指针上的值,而是将整数值乘以数据类型的大小。

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

我们来计算一下:

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

向指针添加值的示例指针

在下面的例子中,我们声明了一个数组和指向数组的指针。使用数组的第一个元素初始化指针,然后将一个整数值 (2) 添加到指针以获取数组的第三个元素。

#include <stdio.h>

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

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

  //在 ptrArr 中添加 2
  ptrArr = ptrArr + 2;

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

  return 0;
}

输出

Value at ptrArr: 12
Value at ptrArr after adding 2: 45

指针减法示例

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

#include <stdio.h>

int main() {
  int int_arr[] = {12, 23, 45, 67, 89};
  int *ptrArr = &int_arr[4]; // 指向最后一个元素

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

  // 将 ptrArr 减 2
  ptrArr = ptrArr - 2;

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

  return 0;
}

输出

Value at ptrArr: 89
Value at ptrArr after adding 2: 45

指针减法

我们熟悉"+"和"-"运算符,它们用于常规数字操作数。然而,当将这些运算符用于指针时,它们的行为略有不同。

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

但是,两个指针的减法是现实可行的。它返回可容纳两个指针的数据类型的数量。

两个指针相减的示例

我们以上面示例中的数组为例,对 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]; // 第零个元素
    int *y = &a[9]; // 最后一个元素
    
    printf("Add of a[0]: %ld add of a[9]: %ld
    ", 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 个整数。

指针比较

可以使用关系运算符(例如"=="、"<"和">")来比较指针。如果"p1"和"p2"指向彼此相关的变量(例如同一数组的元素),则可以对"p1"和"p2"进行有意义的比较。

比较指针的示例

在下面的示例中,我们声明两个指针,并分别用数组的第一个和最后一个元素初始化它们。只要第一个变量指针指向的地址小于或等于数组最后一个元素的地址,即"&var[MAX 1]"(即第二个指针),我们就会不断增加第一个变量指针。

#include <stdio.h>

const int MAX = 3;

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

  // 初始化指针
  ptr1 = var;
  ptr2 = &var[MAX - 1];

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

    /* 指向前一个位置 */
    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