个人主页-爱因斯晨
文章专栏-C语言
加油哦~各位!

一、指针的本质
-
定义:指针是一种变量,专门用于存储内存地址,其大小通常为 4 字节(32 位系统)或 8 字节(64 位系统)
-
核心价值:
- 直接操作内存,提升程序执行效率
- 实现函数多值返回
- 为动态内存分配提供支持
- 实现数据结构(链表、树等)
-
声明方式 :
数据类型 *指针变量名
cint *p; // 声明一个指向int类型的指针p char *str; // 声明一个指向char类型的指针str
二、指针与地址的关系
-
取地址运算符(&):获取变量的内存地址
cint a = 10; int *p = &a; // 将变量a的地址赋值给指针p
-
解引用运算符(*):通过地址访问变量的值
cprintf("%d", *p); // 输出指针p所指向的变量值,即10 *p = 20; // 修改指针p所指向的变量值
-
NULL 指针:不指向任何有效内存的指针
cint *p = NULL; // 初始化空指针 if (p == NULL) { // 判断指针是否为空 // 处理空指针情况 }
三、指针与变量的结合使用
-
指针变量的初始化
cint a = 5; int *p1; // 未初始化的指针(野指针,危险!) int *p2 = &a; // 正确初始化,指向变量a int *p3 = NULL; // 初始化为空指针
-
指针的运算
- 指针 ± 整数:移动指针指向的位置
cint arr[5] = {1,2,3,4,5}; int *p = arr; p++; // 指针向后移动一个int类型的大小(通常4字节)
- 指针 - 指针:计算两个指针之间的元素个数
cint len = &arr[4] - &arr[0]; // 结果为4(元素个数差)
-
多级指针:指向指针的指针
cint a = 10; int *p = &a; // 一级指针 int **pp = &p; // 二级指针 printf("%d", **pp); // 输出10
四、指针与数组的关系
-
数组名的特性:数组名代表数组首元素的地址(常量指针)
cint arr[5] = {1,2,3,4,5}; printf("%p", arr); // 输出数组首元素地址 printf("%p", &arr[0]); // 与上面输出相同
-
指针访问数组元素
c// 以下两种方式等价 arr[2] = 10; *(arr + 2) = 10;
-
数组指针(指向数组的指针)
cint (*p)[5]; // 指向包含5个int元素的数组的指针 int arr[5] = {1,2,3,4,5}; p = &arr; // p指向整个数组
-
指针数组(元素为指针的数组)
cint *p[5]; // 包含5个int*指针的数组 int a = 1, b = 2, c = 3; p[0] = &a; p[1] = &b; p[2] = &c;
五、指针与函数的关系
-
函数参数传递
- 值传递:函数内部修改不影响外部变量
- 指针传递:函数内部可修改外部变量
cvoid swap(int *x, int *y) { int temp = *x; *x = *y; *y = temp; } // 调用方式 int a = 3, b = 5; swap(&a, &b); // a和b的值会被交换
-
函数返回指针
cint *createArray(int size) { int *arr = malloc(size * sizeof(int)); return arr; // 返回动态分配内存的指针 }
-
函数指针(指向函数的指针)
cint add(int a, int b) { return a + b; } int (*funcPtr)(int, int); // 声明函数指针 funcPtr = add; // 函数指针指向add函数 int result = funcPtr(3, 5); // 调用函数,结果为8
六、指针与字符串
-
字符串的两种表示形式
cchar str1[] = "hello"; // 字符数组 char *str2 = "world"; // 字符串常量指针
-
指针操作字符串
cchar *str = "hello"; while (*str != '\0') { printf("%c", *str); str++; // 移动指针访问下一个字符 }
-
字符串处理函数与指针
c#include <string.h> char *src = "hello"; char dest[20]; strcpy(dest, src); // 字符串复制 int len = strlen(src); // 获取字符串长度
七、动态内存分配与指针
-
malloc 函数:分配指定字节数的内存
cint *p = (int*)malloc(5 * sizeof(int)); // 分配5个int的内存 if (p == NULL) { // 内存分配失败处理 }
-
calloc 函数:分配内存并初始化为 0
cint *p = (int*)calloc(5, sizeof(int)); // 分配5个int并初始化为0
-
realloc 函数:重新调整已分配内存的大小
cp = (int*)realloc(p, 10 * sizeof(int)); // 将内存调整为10个int
-
free 函数:释放动态分配的内存
cfree(p); // 释放内存 p = NULL; // 避免野指针
八、指针使用的常见错误
-
野指针:未初始化的指针或指向已释放内存的指针
cint *p; // 野指针,危险! *p = 10; // 未定义行为
-
空指针解引用:对 NULL 指针使用解引用运算符
cint *p = NULL; *p = 5; // 程序崩溃
-
内存泄漏:动态分配的内存未释放
cint *p = (int*)malloc(sizeof(int)); // 忘记调用free(p),导致内存泄漏
-
指针越界:访问超出数组范围的内存
cint arr[5]; int *p = arr; p[10] = 3; // 越界访问,可能导致程序崩溃
九、指针的实际应用场景
- 高效处理大型数据:避免数据拷贝,直接传递地址
- 实现数据结构:链表、树、图等都依赖指针实现
- 函数回调机制:通过函数指针实现事件处理
- 动态数据结构:根据需要动态分配和释放内存
- 操作硬件设备:直接访问特定内存地址控制硬件