当前位置: 首页 > news >正文

C 语言的指针复习笔记

用着用着就糊涂了,重新复习一下。。。。。。。。

内容由 AI 生成

        C 语言的指针是其最核心、最具特色的特性之一,理解指针是掌握 C 语言的关键。指针本质上是存储内存地址的变量,通过指针可以直接操作内存中的数据,这使得 C 语言具备高效、灵活的特性,但也增加了学习难度。以下从基础到进阶详细讲解指针的用法:

一、指针的基本概念

  • 内存地址:计算机内存被划分为一个个字节,每个字节都有唯一的编号(类似门牌号),这个编号就是内存地址(通常用十六进制表示,如0x7ffd8a5b5a4c)。
  • 指针变量:专门用于存储内存地址的变量,其值是另一个变量(或内存空间)的地址。
  • 指针的意义:通过指针可以间接访问或修改其指向的内存空间中的数据,尤其在处理数组、函数参数传递、动态内存分配等场景中不可替代。

二、指针的声明与初始化

1. 指针的声明

指针声明的基本语法:数据类型 *指针名;

  • 数据类型:指针所指向的变量的数据类型(决定了通过指针操作内存时的 "步长",如int*每次操作 4 字节,char*每次操作 1 字节)。
  • *:表示该变量是指针类型。
  • 指针名:遵循标识符命名规则。

示例:

int *p;       // 声明一个指向int类型的指针p
char *cp;     // 声明一个指向char类型的指针cp
float *fp;    // 声明一个指向float类型的指针fp
2. 指针的初始化(指向有效内存)

        指针必须初始化后才能使用(否则可能成为 "野指针",操作未知内存导致程序崩溃)。初始化的核心是让指针存储一个有效变量的地址

通过&(取地址运算符)获取变量的地址,赋值给指针:

int a = 10;
int *p = &a;  // 指针p指向变量a(p存储a的地址)

 

注意:指针的类型必须与所指向变量的类型一致(除非进行强制类型转换),例如char*不能直接指向int变量。

三、指针的核心操作

1. 解引用(访问指向的内容)

通过*(解引用运算符)可以访问指针所指向的内存中的数据。

示例:

int a = 10;
int *p = &a;printf("a的值:%d\n", a);       // 直接访问a:10
printf("p存储的地址:%p\n", p); // 输出a的地址(如0x7ffd8a5b5a4c)
printf("p指向的值:%d\n", *p);  // 解引用p,获取a的值:10

通过指针修改指向的变量的值:

*p = 20;  // 等价于 a = 20(通过p间接修改a的值)
printf("修改后a的值:%d\n", a);  // 输出20
2. 指针的赋值与比较
  • 指针之间可以直接赋值(让两个指针指向同一块内存):

    int a = 10;
    int *p = &a;
    int *q = p;  // q和p指向同一个变量a
    printf("*q的值:%d\n", *q);  // 输出10
    
  • 指针可以比较(判断是否指向同一块内存):

    if (p == q) {printf("p和q指向同一块内存\n");  // 条件成立
    }
    

四、指针与数组

数组和指针关系密切,数组名本质上是指向数组首元素的指针常量(不能被修改)。

1. 数组名作为指针
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;  // 等价于 p = &arr[0](arr是首元素地址)// 访问数组元素的两种方式
printf("arr[0] = %d\n", arr[0]);  // 数组下标法:1
printf("*p = %d\n", *p);          // 指针解引用:1
2. 指针的算术运算(核心)

指针的加减运算以 "所指向类型的大小" 为步长(而非字节):

  • p++:指针向后移动一个元素(对于int*,移动 4 字节;char*移动 1 字节)。
  • p + i:指针向后移动 i 个元素(指向arr[i])。

示例:

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;for (int i = 0; i < 5; i++) {printf("%d ", *(p + i));  // 等价于 arr[i],输出:1 2 3 4 5
}

注意:指针越界访问(如访问p+5及以外的地址)是未定义行为,可能导致程序崩溃。

3. 指针与二维数组

二维数组可以理解为 "数组的数组",其数组名是指向首行(一维数组)的指针。

示例:

int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*p)[3] = arr;  // p是指向"包含3个int的数组"的指针(与二维数组匹配)printf("%d\n", *(*(p + 0) + 1));  // 访问第0行第1列:2
printf("%d\n", *(*(p + 1) + 2));  // 访问第1行第2列:6

五、指针与函数

        指针作为函数参数或返回值,可以实现对函数外部变量的修改、传递大型数据(避免拷贝开销)等功能。

1. 指针作为函数参数(传址调用)

        C 语言函数参数默认是 "值传递"(形参是实参的拷贝,修改形参不影响实参)。通过指针传递变量地址,可以在函数内部修改外部变量的值。

示例:交换两个变量的值

// 错误示例:值传递无法交换
void swap1(int x, int y) {int temp = x;x = y;y = temp;  // 仅修改形参x、y,实参不变
}// 正确示例:指针传递(传址)
void swap2(int *x, int *y) {int temp = *x;  // 解引用获取x指向的值*x = *y;        // 修改x指向的变量*y = temp;      // 修改y指向的变量
}int main() {int a = 10, b = 20;swap1(a, b);printf("swap1后:a=%d, b=%d\n", a, b);  // 仍为10,20(未交换)swap2(&a, &b);  // 传递a和b的地址printf("swap2后:a=%d, b=%d\n", a, b);  // 交换为20,10return 0;
}
2. 指针作为函数返回值(指针函数)

        函数可以返回指针(指向某个内存空间),但需注意:不能返回函数内部局部变量的地址(局部变量在函数结束后被释放,其地址变为无效)。

示例:返回静态变量的地址(静态变量生命周期与程序一致)

int* get_num() {static int num = 100;  // 静态变量,存储在全局区return &num;           // 返回有效地址
}int main() {int *p = get_num();printf("%d\n", *p);  // 输出100(有效)return 0;
}
3. 函数指针(指向函数的指针)

        函数指针是指向函数的指针变量,其值是函数的入口地址。可用于实现回调函数(如排序算法中的比较函数)。

声明语法:返回值类型 (*指针名)(参数列表);

示例:

// 定义一个加法函数
int add(int a, int b) {return a + b;
}int main() {int (*fptr)(int, int);  // 声明函数指针fptr(指向"参数为int,int,返回int的函数")fptr = add;             // fptr指向add函数(函数名即地址)int result = fptr(3, 5);  // 通过函数指针调用add,等价于(*fptr)(3,5)printf("3+5=%d\n", result);  // 输出8return 0;
}

六、多级指针(指向指针的指针)

多级指针是指向指针的指针,常用于处理 "指针的地址"(如二维数组、动态分配的指针数组等)。

语法:数据类型 **指针名;**表示二级指针,***表示三级指针,以此类推)

示例:二级指针

int a = 10;
int *p = &a;    // p是一级指针(指向a)
int **pp = &p;  // pp是二级指针(指向p)// 访问a的值
printf("a = %d\n", a);        // 直接访问:10
printf("*p = %d\n", *p);      // 一级解引用:10
printf("**pp = %d\n", **pp);  // 二级解引用:10

应用场景:通过二级指针修改一级指针的指向

void change_ptr(int **pp) {static int b = 20;*pp = &b;  // 修改pp所指向的指针(p)的指向,使其指向b
}int main() {int a = 10;int *p = &a;printf("修改前*p = %d\n", *p);  // 10change_ptr(&p);  // 传递p的地址(二级指针参数)printf("修改后*p = %d\n", *p);  // 20(p现在指向b)return 0;
}

七、指针与动态内存分配

        C 语言通过malloccallocreallocfree函数在堆区动态分配内存,这些函数的返回值是指向分配内存的指针。

1. 动态分配内存(malloc
#include <stdlib.h>  // 包含动态内存函数int main() {int n = 5;// 分配n个int类型的内存(总大小:n * sizeof(int))int *arr = (int*)malloc(n * sizeof(int));  // 返回void*,需强制转换为int*if (arr == NULL) {  // 内存分配失败时返回NULL,必须检查printf("内存分配失败\n");return 1;}// 使用动态数组for (int i = 0; i < n; i++) {arr[i] = i + 1;}// 释放内存(堆区内存不会自动释放,必须手动释放)free(arr);arr = NULL;  // 避免野指针(释放后指针仍存储原地址,需置空)return 0;
}

2. 其他动态内存函数
  • calloc(n, size):分配 n 个大小为 size 的内存,并初始化为 0(malloc不初始化)。
  • realloc(ptr, new_size):调整已分配内存的大小(可能迁移内存地址)。

八、指针的常见错误与注意事项

  1. 野指针:未初始化或已释放的指针(指向无效内存)。
    避免:指针声明后立即初始化(如int *p = NULL;),释放后置空(p = NULL;)。

  2. 空指针解引用:对NULL指针使用*操作(NULL是无效地址0)。
    避免:解引用前检查指针是否为NULLif (p != NULL) { ... })。

  3. 指针越界:访问超出数组或动态内存范围的地址。
    避免:严格控制指针运算的范围(如循环变量不超过数组长度)。

  4. 内存泄漏:动态分配的内存未用free释放,导致内存被永久占用。
    避免:确保mallocfree配对使用,释放后指针置空。

  5. 指针类型不匹配:不同类型的指针直接赋值(如char* p = &a;,a 是 int 类型)。
    避免:如需转换,使用显式强制类型转换(char* p = (char*)&a;),但需谨慎(可能导致访问错误)。

总结

指针是 C 语言的灵魂,其核心是 "通过地址间接操作内存"。掌握指针需要理解:

  • 指针的声明与初始化(指向有效内存);
  • 解引用(*)和取地址(&)的操作;
  • 指针与数组、函数的结合使用;
  • 动态内存分配中指针的管理;
  • 规避野指针、内存泄漏等常见错误。

http://www.dtcms.com/a/291517.html

相关文章:

  • 圆柱电池自动分选机:全流程自动化检测的革新之路
  • 大模型中的Actor-Critic机制
  • 嵌入式学习笔记--MCU阶段--DAY08总结
  • 【Java基础03】Java变量2
  • seata at使用
  • 自然语言推理技术全景图:从基准数据集到BERT革命
  • 设备虚拟化技术-IRF
  • 利用DeepSeek编写批量输出多个主机的磁盘状况的脚本
  • 携“养鲜”魔法赴中卫,容声冰箱让石头缝里的鲜甜走得更远
  • 前端之学习后端java小白(一)之SDKMAN及helloword
  • EcoVadis评估:为企业带来的多重价值与竞争优势
  • QT跨平台应用程序开发框架(11)—— Qt系统相关
  • STM32F1使用volatile关键字避免内存优化
  • 基于springboot+vue开发的图书馆座位预约系统【源码+sql+可运行】【50721
  • 在安卓开发中,多次点击启动 Service 会有什么问题?
  • 关键成功因素法(CSF)深度解析:从战略目标到数据字典
  • 后训练(Post-training)语言模型
  • NuGet02-包制作及管理
  • 本地部署Nacos开源服务平台,并简单操作实现外部访问,Windows 版本
  • Oracle数据库索引性能机制深度解析:从数据结构到企业实践的系统性知识体系
  • 【python数据结构算法篇】python数据结构
  • 数据库的介绍和安装
  • Qualcomm Linux 蓝牙指南学习--验证 Fluoride 协议栈的功能(2)
  • day59-可观测性建设-zabbix自定义监控项
  • Shell 脚本编程全面学习指南
  • AK视频下载工具:免费高效,多平台支持
  • 解决图片方向混乱问题的自动化处理方案
  • 51c大模型~合集157
  • 《基于单层软皮和高密度电阻抗层析成像的多模态信息结构》论文解读
  • Python图像处理基础(十)