1、指针运算
指针运算是指对指针进行加法、减法、比较等操作。指针本身是存储内存地址的变量,指针运算就是对内存地址进行操作,通常用于遍历数组和动态内存分配。
1)指针加法(指针递增)
当对指针执行加法操作时,指针将增加一个元素的大小,而不是字节。比如,对于一个 int*
指针,指针加1实际上是将指针向前移动 sizeof(int)
字节的位置。
#include <stdio.h>
int main() {
// 初始化数组
int arr[] = {1, 2, 3};
// 指针指向数组的第一个元素
int* ptr = arr;
// 打印原始数组元素
printf("原始数组元素:\n");
for (int i = 0; i < 3; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
// 使指针 ptr 指向 arr[1]
ptr++;
// 打印指针指向的元素
printf("\n指针指向的新位置:\n");
printf("ptr 指向的元素: %d\n", *ptr); // ptr 现在指向 arr[1]
// 继续移动指针到 arr[2]
ptr++;
// 打印指针指向的元素
printf("ptr 指向的元素: %d\n", *ptr); // ptr 现在指向 arr[2]
return 0;
}
2)指针减法(指针递减)
与加法相反,指针减法使指针向后移动,指向前一个元素。
#include <stdio.h>
int main() {
// 初始化数组
int arr[] = {10, 20, 30, 40, 50};
// 创建指针,指向 arr[2]
int* ptr2 = arr + 2;
// 输出指针指向的元素
printf("ptr2 指向 arr[2]: %d\n", *ptr2); // 输出 30
// ptr2 指向前一个元素,即 arr[1]
ptr2--;
// 输出指针指向的新位置的元素
printf("ptr2 现在指向 arr[1]: %d\n", *ptr2); // 输出 20
return 0;
}
3)指针之间的运算
指针相减时,结果是指针之间的差值,以元素的个数为单位,而不是字节数。
#include <stdio.h>
int main() {
// 定义一个整数数组
int arr[] = {10, 20, 30, 40, 50};
// 指针 ptr1 指向数组的第一个元素
int* ptr1 = arr;
// 指针 ptr2 指向数组的第三个元素 (索引为2)
int* ptr2 = arr + 2;
// 计算 ptr2 和 ptr1 之间的距离 (以元素为单位)
ptrdiff_t diff = ptr2 - ptr1;
// 输出 ptr2 和 ptr1 之间的差值
printf("diff = %td\n", diff); // diff = 2
return 0;
}
2、void 指针
void
指针是一个特殊类型的指针,它可以指向任何类型的数据,但是不能直接解引用,因为它不指定指向的数据类型。为了对
void
指针进行操作,必须先将其转换为某个具体类型的指针。void*
可以指向任何类型的数据,但不能直接进行解引用或指针运算。
1)void 指针的使用
为了使 void
指针能够解引用,必须先将它转换为其他类型的指针。
#include <stdio.h>
int main() {
int num = 10;
// 将 num 的地址赋值给 void* 指针
void* ptr = #
// 将 void* 转换为 int* 类型并解引用,输出 num 的值
printf("%d\n", *(int*)ptr); // 输出 10
return 0;
}
2)void 指针与数组
void
指针不能直接进行指针运算,因此通常会先将其转换为特定类型的指针来进行运算。
#include <stdio.h>
int main() {
int arr[] = {1, 2, 3};
// 将 arr 的地址赋值给 void* 指针
void* ptr = arr;
// 需要先将 void* 转换为 int* 然后进行指针运算
printf("%d\n", *((int*)ptr + 1)); // 输出 2
return 0;
}
3)void 指针的常见用途
通用函数接口,如 malloc()
函数返回的是 void*
,它可以指向任何类型的数据。回调函数通常通过 void*
来传递不确定类型的参数。
#include <stdio.h>
// 回调函数类型
typedef void (*Callback)(void*);
// 回调函数示例1:打印整数
void printInt(void* data) {
int* ptr = (int*)data;
printf("Integer: %d\n", *ptr);
}
// 回调函数示例2:打印字符串
void printString(void* data) {
char* str = (char*)data;
printf("String: %s\n", str);
}
// 通用的函数,接受回调函数和数据
void applyOperation(Callback callback, void* data) {
callback(data); // 调用回调函数
}
int main() {
int num = 42;
char str[] = "Hello, world!";
// 使用不同类型的数据调用相同的函数
applyOperation(printInt, &num); // 输出:Integer: 42
applyOperation(printString, str); // 输出:String: Hello, world!
return 0;
}
3、对 void 指针进行指针运算
为了对 void
指针进行指针运算,需要将 void
指针强制转换为某种特定类型的指针。因为编译器需要知道指针所指向数据的大小,以便在进行指针运算时正确计算内存地址。
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
void *ptr = arr; // `void` 指针指向数组的开始
size_t n = 3; // 移动 3 个元素
// 将指针递增 `n` 个 `int` 类型的元素
ptr = (int *)ptr + n;
// 现在 `ptr` 指向 `arr[3]`
printf("指针指向的值是: %d\n", *(int *)ptr); // 输出: 40
return 0;
}