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; }