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

C语言学习——指针部分知识点归纳

C语言指针知识要点整理

一、指针基础概念

1. 什么是指针?

•指针是存储内存地址的变量​
•指针本身也有自己的内存地址
•通过指针可以间接访问和操作内存中的数据

2. 指针的声明和初始化

// 声明指针
int *p;        // 指向整型的指针
float *fp;     // 指向浮点数的指针
char *cp;      // 指向字符的指针
// 指针的初始化
int x = 10;
int *p = &x;   // p指向x的地址
// NULL指针
int *p = NULL; // 空指针,指向地址0

二、指针运算符

1. 取地址运算符 &

•获取变量的内存地址

int a = 5;
int *p = &a;  // p存储a的地址

2. 解引用运算符 *

•访问指针所指向地址的值

int a = 5;
int *p = &a;
int b = *p;   // b = 5
*p = 20;      // 通过指针修改a的值,现在a = 20

三、指针的运算

1. 算术运算

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;     // p指向arr[0]
p++;              // p现在指向arr[1],地址增加sizeof(int)字节
p--;              // p指向arr[0]
p = p + 3;        // p指向arr[3]
int *q = p - 2;   // q指向arr[1]
  1. 关系运算
int *p, *q;
if(p == q)  // 比较两个指针是否指向同一地址
if(p < q)   // 比较指针地址的大小
if(p != NULL) // 检查指针是否非空

四、指针与数组

1. 数组名就是指针

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;  // 等价于 int *p = &arr[0];
// 通过指针访问数组元素
*(arr + 2) = 10;     // arr[2] = 10
*(p + 3) = 20;       // arr[3] = 20

2. 指针遍历数组

int arr[5] = {1, 2, 3, 4, 5};
int *p;
// 方法1
for(p = arr; p < arr + 5; p++) {printf("%d ", *p);}
// 方法2
p = arr;
for(int i = 0; i < 5; i++) {printf("%d ", *(p + i));
}

五、多级指针

1. 二级指针

int a = 10;
int *p = &a;    // 一级指针
int **pp = &p;  // 二级指针,指向指针的指针
// 访问
printf("%d\n", a);    // 10
printf("%d\n", *p);   // 10
printf("%d\n", **pp); // 10

六、指针与函数

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

// 交换两个变量的值
void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}
int main() {int x = 5, y = 10;swap(&x, &y);  
// 传递地址return 0;
}

2. 指针作为函数返回值

// 返回数组最大值的地址
int* findMax(int arr[], int n) {int *max = &arr[0];for(int i = 1; i < n; i++) {if(arr[i] > *max) {max = &arr[i];}}return max;  // 返回指针
}

七、指针与字符串

1. 字符指针

// 字符串字面量
char *str = "Hello";  // str指向字符串常量
// str[0] = 'h';  // 错误!不能修改字符串常量
// 字符数组
char arr[] = "World";  // 可以修改
arr[0] = 'w';         // 正确

2. 常用字符串函数

char str1[20] = "Hello";
char str2[] = "World";
char *p;
p = strcpy(str1, str2);  // 字符串复制
p = strcat(str1, str2);  // 字符串连接
int len = strlen(str1);  // 字符串长度
p = strchr(str1, 'l');   // 查找字符

八、特殊指针

1. 空指针 NULL

•表示指针不指向任何有效地址
•使用前应检查是否为NULL

int *p = NULL;
if(p != NULL) {*p = 10;  // 安全访问
}

2. 野指针

•指向无效内存地址的指针
•未初始化的指针
•已释放内存的指针

int *p;           // 野指针,未初始化
*p = 10;          // 危险!可能崩溃
int *p = (int*)malloc(sizeof(int));
free(p);          // 释放内存
*p = 20;          // 野指针,危险!
p = NULL;         // 好习惯:释放后置为NULL

3. void 指针

•通用类型指针,可指向任意数据类型
•不能直接解引用,需先转换为具体类型

int a = 10;
float b = 3.14;
void *vp;
vp = &a;  // 指向int
*(int*)vp = 20;  // 需要类型转换
vp = &b;  // 指向float
printf("%f\n", *(float*)vp);

九、指针与动态内存分配

  1. 动态内存管理函数
#include <stdlib.h>
// 分配内存
int *p = (int*)malloc(10 * sizeof(int));  // 分配10个int空间
if(p == NULL) {
// 处理内存分配失败
}
// 重新分配内存
p = (int*)realloc(p, 20 * sizeof(int));  // 调整为20个int
// 释放内存
free(p);
p = NULL;  // 好习惯

十、指针与结构体

1. 结构体指针

typedef struct {int id;char name[20];float score;
} Student;
Student s = {1, "Tom", 90.5};
Student *p = &s;
// 访问成员
(*p).id = 2;    // 方式1
p->id = 3;       // 方式2(更常用)
strcpy(p->name, "Jerry");

2. 指针在结构体中的使用

typedef struct Node {int data;struct Node *next;  // 指向自身类型的指针
} Node;
// 创建链表节点
Node *createNode(int value) {Node *newNode = (Node*)malloc(sizeof(Node));newNode->data = value;newNode->next = NULL;return newNode;
}

十一、函数指针

1. 函数指针声明和使用

// 函数原型
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int main() {// 声明函数指针int (*funcPtr)(int, int);// 指向add函数funcPtr = add;printf("%d\n", funcPtr(5, 3));  // 8// 指向sub函数funcPtr = sub;printf("%d\n", funcPtr(5, 3));  // 2return 0;
}

2. 函数指针作为参数

int calculate(int a, int b, int (*operation)(int, int)) {return operation(a, b);
}int result = calculate(10, 5, add);  // 15

十二、易错点和注意事项

1. 常见错误

// 错误1:使用未初始化的指针
int *p;
*p = 10;  // 段错误
// 错误2:返回局部变量的地址
int* badFunction() {int x = 10;return &x;  // x是局部变量,函数结束就销毁
}
// 错误3:指针类型不匹配
float f = 3.14;
int *p = &f;  // 错误类型
printf("%d\n", *p);  // 输出错误

2. 最佳实践

1.初始化指针​:声明时立即初始化
2.​检查NULL​:使用前检查指针是否为空
3.​匹配类型​:确保指针类型与指向的数据类型匹配
4.及时释放​:动态分配的内存要及时释放
5.​避免野指针​:释放内存后置为NULL
6.注意作用域​:不要返回局部变量的地址

十三、练习理解

指针与数组等价性

int arr[5] = {1, 2, 3, 4, 5};
// 以下表达式是等价的:
arr[2]    ≡ *(arr + 2)    ≡ *(2 + arr)    ≡ 2[arr]
// 是的,2[arr] 是合法的C语法!

指针的指针

int a = 10;
int *p = &a;
int **pp = &p;
int ***ppp = &pp;
// 访问a的值
printf("%d\n", a);      // 10
printf("%d\n", *p);     // 10
printf("%d\n", **pp);   // 10
printf("%d\n", ***ppp); // 10
http://www.jsqmd.com/news/130729/

相关文章:

  • 线代强化NO20|矩阵的相似与相似对角化|综合运用 - 实践
  • 93 年 32 岁 IT 运维失业了!甲方不续约项目解散,你们有同款经历吗?
  • 东方博宜OJ 1694:装信封问题 ← 递归
  • 2025年论文写作终极指南:8款免费AI神器,20分钟速成初稿,全学科覆盖!
  • MyListing – 目录与列表 WordPress 主题
  • 直线模组:工业自动化的精度心脏
  • 基于90分钟Maven项目实战入门——邮件群发工具(模拟版)
  • Web 漏洞扫描入门的集合!2025 十大工具详细拆解,你用过哪几个?
  • AI元人文构想:从价值对齐到意义共生的范式革命与文明演进新路径(人机协作)
  • 1688商品采集API实战指南:从接入到数据落地全流程
  • 低代码平台核心功能拆解:拖拽式开发与可视化配置详解
  • 【学习笔记】《道德经》第22章
  • temu,shein销量提升秘籍:测评技巧与风险规避全解析
  • python in visual studio 2022: for pip installing packages
  • 谁懂 30 + 职场人的无奈?网安行业越老越吃香,告别 35 岁焦虑,282G 学习资源速码!
  • Java 爬虫对百科词条分类信息的抓取与处理
  • OBS直播教程:OBS如何添加歌词显示?OBS怎么把歌词放上去?
  • 软件工程课程学期总结与收获
  • 云南抖音服务商慧多派实力机构,不能错过!
  • LIS2DW12三轴加速度传感器原理图设计,已量产(加速度传感器)
  • 失业 3 个月投 127 份简历?网安零成本转行月薪 12K,你们敢试吗?
  • 【路径规划】基于RRT APF RRT+APF RRT星+APF实现机器人路径规划附matlab代码
  • AJAX本质与核心概念
  • 比话和其他降AI率工具有什么不同,为什么能把知网AI率降低到15%
  • 中山SEO公司:如何在2026年拥抱AI技术,打造差异化竞争优势
  • 满足!** 豆角鸡蛋西红柿捞面 **
  • python执行动态代码方案
  • java计算机毕业设计无人超市支付系统设计与实现 智慧门店自助结算系统设计与实现 无人零售扫码支付平台开发实战
  • 实用指南:CentOS 7 Docker 部署 DVWA 教程
  • day46_Grad-CAM@浙大疏锦行