在 C 语言中,指针可以进行一些特定的运算,主要包括以下几种:
一、指针与整数的加减运算
- 加法运算:
-
- 当指针与一个整数相加时,指针会根据其所指向的数据类型的大小向前移动相应的字节数。
- 例如,假设指针 p 指向一个 int 类型的数组,int arr[5] = {1, 2, 3, 4, 5}; int *p = arr;,如果执行 p + 2,那么 p 现在指向 arr[2],因为 int 类型通常占用 4 个字节,所以 p + 2 表示将指针向前移动了 2 * 4 = 8 个字节。
- 减法运算:
-
- 指针相减通常用于计算两个指针之间的元素个数。
- 例如,int arr[5] = {1, 2, 3, 4, 5}; int *p1 = arr; int *p2 = arr + 3;,那么 p2 - p1 的结果为 3,表示 p2 和 p1 之间相差 3 个 int 类型的元素。
二、指针的关系运算
- 比较运算:
-
- 可以使用关系运算符(如 、>、、>=、==、!=)对指针进行比较。
- 指针的比较通常是基于它们所指向的内存地址的顺序进行的。如果一个指针指向的内存地址小于另一个指针指向的内存地址,则前者被认为小于后者。
- 例如,int arr[5] = {1, 2, 3, 4, 5}; int *p1 = arr; int *p2 = arr + 2;,在大多数情况下,p1 < p2 会返回 true,因为 p1 指向的地址小于 p2 指向的地址。
- 递增递减运算:
-
- ++ 和 -- 运算符可以用于指针,使指针指向下一个或上一个元素。
- 如果指针指向一个数组元素,++ 操作会使指针指向下一个元素,-- 操作会使指针指向上一个元素。
- 例如,int arr[5] = {1, 2, 3, 4, 5}; int *p = arr; ++p; 现在 p 指向 arr[1]。
三、注意事项
- 指针运算的有效性:
-
- 进行指针运算时,要确保运算结果指向合法的内存地址。例如,在对指针进行递增或递减操作时,不能超出其所指向的数组范围,否则会导致未定义行为。
- 不同类型指针的运算:
-
- 不同类型的指针进行运算时可能会产生不可预测的结果。一般情况下,应该只对指向相同类型的指针进行运算。
- 指针运算与内存安全:
-
- 错误的指针运算可能导致访问非法内存,从而使程序崩溃。在进行指针运算时,要特别注意内存边界和指针的有效性。
四、实例
递增一个指针
#include <stdio.h>
const int MAX = 3;
int main ()
{
// 定义一个整数数组
int var[] = {10, 100, 200};
// 定义一个整数变量 i 和一个整数指针 ptr
int i, *ptr;
// 将指针 ptr 指向数组 var 的起始地址
ptr = var;
// 循环遍历数组
for ( i = 0; i < MAX; i++)
{
// 打印当前指针 ptr 所指向的地址
printf("存储地址:var[%d] = %p\n", i, ptr );
// 打印当前指针 ptr 所指向地址的值
printf("存储值:var[%d] = %d\n", i, *ptr );
// 将指针 ptr 移动到下一个数组元素的位置
ptr++;
}
return 0;
}
上面代码被编译和执行后,会产生下列结果:
存储地址:var[0] = e4a298cc
存储值:var[0] = 10
存储地址:var[1] = e4a298d0
存储值:var[1] = 100
存储地址:var[2] = e4a298d4
存储值:var[2] = 200
递增字符指针:
#include <stdio.h>
int main() {
char str[] = "Hello";
char *ptr = str; // 指针指向字符串的第一个字符
printf("初始字符: %c\n", *ptr); // 输出 H
ptr++; // 递增指针,使其指向下一个字符
printf("递增后字符: %c\n", *ptr); // 输出 e
return 0;
}
在这个示例中,ptr++ 使指针从 str[0] 指向 str[1]。因为 ptr 是一个 char 类型指针,所以它递增时会移动 sizeof(char) 个字节,即 1 个字节。
当上面的代码被编译和执行时,它会产生下列结果:
初始字符: H
递增后字符: e
递增结构体组织:
#include <stdio.h>
struct Point {
int x;
int y;
};
int main() {
struct Point points[] = {{1, 2}, {3, 4}, {5, 6}};
struct Point *ptr = points; // 指针指向结构体数组的第一个元素
printf("初始点: (%d, %d)\n", ptr->x, ptr->y); // 输出 (1, 2)
ptr++; // 递增指针,使其指向下一个结构体
printf("递增后点: (%d, %d)\n", ptr->x, ptr->y); // 输出 (3, 4)
return 0;
}
在这个示例中,ptr++ 使指针从 points[0] 指向 points[1]。因为 ptr 是一个 struct Point 类型指针,所以它递增时会移动 sizeof(struct Point) 个字节。
当上面的代码被编译和执行时,它会产生下列结果:
初始点: (1, 2)
递增后点: (3, 4)
递减一个指针
递减一个指针意味着让指针指向前一个内存位置。和递增指针类似,指针的递减操作也会根据指针所指向的数据类型进行适当的内存偏移。
对指针进行递减运算,即把值减去其数据类型的字节数,如下所示:
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = &arr[4]; // 指针指向数组的最后一个元素
printf("初始值: %d\n", *ptr); // 输出 50
ptr--; // 递减指针,使其指向前一个整数元素
printf("递减后值: %d\n", *ptr); // 输出 40
ptr--; // 再次递减指针
printf("再次递减后值: %d\n", *ptr); // 输出 30
return 0;
}
结果:
初始值: 50
递减后值: 40
再次递减后值: 30
递减结构体指针:
#include <stdio.h>
struct Point {
int x;
int y;
};
int main() {
struct Point points[] = {{1, 2}, {3, 4}, {5, 6}};
struct Point *ptr = &points[2]; // 指针指向结构体数组的最后一个元素
printf("初始点: (%d, %d)\n", ptr->x, ptr->y); // 输出 (5, 6)
ptr--; // 递减指针,使其指向前一个结构体
printf("递减后点: (%d, %d)\n", ptr->x, ptr->y); // 输出 (3, 4)
ptr--; // 再次递减指针
printf("再次递减后点: (%d, %d)\n", ptr->x, ptr->y); // 输出 (1, 2)
return 0;
}
结果:
初始点: (5, 6)
递减后点: (3, 4)
再次递减后点: (1, 2)
指针的比较
在 C 语言中,可以比较指针来确定它们的关系。指针比较主要用于确定两个指针是否指向相同的内存位置或确定一个指针是否位于另一个指针之前或之后。
指针可以用关系运算符进行比较,如==、!=、、=。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。
以下是一些示例代码,展示了如何比较指针并输出结果。
指针相等比较:
#include <stdio.h>
int main() {
int a = 5;
int b = 10;
int *ptr1 = &a;
int *ptr2 = &a;
int *ptr3 = &b;
if (ptr1 == ptr2) {
printf("ptr1 和 ptr2 指向相同的内存地址\n"); // 这行会被输出
} else {
printf("ptr1 和 ptr2 指向不同的内存地址\n");
}
if (ptr1 != ptr3) {
printf("ptr1 和 ptr3 指向不同的内存地址\n"); // 这行会被输出
} else {
printf("ptr1 和 ptr3 指向相同的内存地址\n");
}
return 0;
}
ptr1 和 ptr2 指向相同的内存地址 ptr1 和 ptr3 指向不同的内存地址
指针大小比较:
#include <stdio.h>
int main() {
int a = 5;
int b = 10;
int *ptr1 = &a;
int *ptr2 = &a;
int *ptr3 = &b;
if (ptr1 == ptr2) {
printf("ptr1 和 ptr2 指向相同的内存地址\n"); // 这行会被输出
} else {
printf("ptr1 和 ptr2 指向不同的内存地址\n");
}
if (ptr1 != ptr3) {
printf("ptr1 和 ptr3 指向不同的内存地址\n"); // 这行会被输出
} else {
printf("ptr1 和 ptr3 指向相同的内存地址\n");
}
return 0;
}
结果:
ptr1 在 ptr2 之前
ptr1 在 ptr2 之前或相同位置
遍历数组并比较指针:
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *start = arr; // 指向数组的第一个元素
int *end = &arr[4]; // 指向数组的最后一个元素
int *ptr;
for (ptr = start; ptr <= end; ptr++) {
printf("当前指针指向的值: %d\n", *ptr);
}
return 0;
}
结果:
当前指针指向的值: 10
当前指针指向的值: 20
当前指针指向的值: 30
当前指针指向的值: 40
当前指针指向的值: 50
总结:
- 相等比较 (== 和 !=): 用于判断两个指针是否指向相同的内存位置。
- 大小比较 (, =): 通常用于指针遍历数组或内存块时,判断一个指针是否在另一个指针之前或之后。