C 指针的算术运算
C 指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。
假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:
ptr++
在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。
我们概括一下:
- 指针的每一次递增,它其实会指向下一个元素的存储单元。
- 指针的每一次递减,它都会指向前一个元素的存储单元。
- 指针在递增和递减时跳跃的字节数取决于指针所指向变量数据类型长度,比如 int 就是 4 个字节。
递增一个指针
递增一个指针意味着让指针指向下一个内存位置。
指针的递增操作会根据指针所指向的数据类型进行适当的内存偏移。
我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,数组可以看成一个指针常量。下面的程序递增变量指针,以便顺序访问数组中的每一个元素:
实例
当上面的代码被编译和执行时,它会产生下列结果:
存储地址:var[0] = e4a298cc 存储值:var[0] = 10 存储地址:var[1] = e4a298d0 存储值:var[1] = 100 存储地址:var[2] = e4a298d4 存储值:var[2] = 200
递增字符指针:
实例
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
递增结构体指针:
实例
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)
递减一个指针
递减一个指针意味着让指针指向前一个内存位置。和递增指针类似,指针的递减操作也会根据指针所指向的数据类型进行适当的内存偏移。
对指针进行递减运算,即把值减去其数据类型的字节数,如下所示:
实例
当上面的代码被编译和执行时,它会产生下列结果:
初始值: 50 递减后值: 40 再次递减后值: 30
递减字符指针:
实例
int main() {
char str[] = "Hello";
char *ptr = &str[4]; // 指针指向字符串的最后一个字符 'o'
printf("初始字符: %c\n", *ptr); // 输出 o
ptr--; // 递减指针,使其指向前一个字符
printf("递减后字符: %c\n", *ptr); // 输出 l
ptr--; // 再次递减指针
printf("再次递减后字符: %c\n", *ptr); // 输出 l
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
初始字符: o 递减后字符: l 再次递减后字符: l
递减结构体指针:
实例
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 进行大小比较。
以下是一些示例代码,展示了如何比较指针并输出结果。
指针相等比较:
实例
当上面的代码被编译和执行时,它会产生下列结果:
ptr1 和 ptr2 指向相同的内存地址 ptr1 和 ptr3 指向不同的内存地址
指针大小比较:
实例
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr1 = &arr[1]; // 指向 arr[1],值为 20
int *ptr2 = &arr[3]; // 指向 arr[3],值为 40
if (ptr1 < ptr2) {
printf("ptr1 在 ptr2 之前\n"); // 这行会被输出
} else {
printf("ptr1 在 ptr2 之后或相同位置\n");
}
if (ptr1 > ptr2) {
printf("ptr1 在 ptr2 之后\n");
} else {
printf("ptr1 在 ptr2 之前或相同位置\n"); // 这行会被输出
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
ptr1 在 ptr2 之前 ptr1 在 ptr2 之前或相同位置
遍历数组并比较指针:
实例
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
总结
- 相等比较 (
==
和!=
): 用于判断两个指针是否指向相同的内存位置。 - 大小比较 (
<
,>
,<=
,>=
): 通常用于指针遍历数组或内存块时,判断一个指针是否在另一个指针之前或之后。
老王
pyt***_go@163.com
用 clang 编译这个程序时会出现一个警告:
编译后的二进制文件执行后,达不到预期结果。
解决办法如下:
老王
pyt***_go@163.com
俊才星驰
984***789@qq.com
楼上的错误很明显,指针类型的变量是16进制地址值,他想的是用%x格式化输出,但是%x输出的是无符号16进制。因为指针类型始终为正值,所以会出现警告,故应该按照示例采用%p输出指针类型
俊才星驰
984***789@qq.com
钓猫的小鱼
218***2862@qq.com
直接使用 ptr=array 时,会默认为数组第一个元素的地址,因此需要在 for 循环里添加一个 prt++ 把变量指针进行递增:
也可以在 for 循环里添加一个 ptr=&array[i] 这样就可以随着 i 的递增,把变量指针进行递增:
钓猫的小鱼
218***2862@qq.com