C 语言基础第16天:指针补充

在 C 语言的学习旅程中,指针无疑是一个核心且颇具挑战性的知识点。指针的灵活运用能让程序更高效,但也容易让人混淆。本文将深入探讨指针的高级应用,包括数组指针、指针数组、字符数组与字符指针、指针函数、函数指针以及二级指针等内容,并结合实例进行详细讲解。

数组指针

数组指针,从名称上看可能会和指针数组混淆,但它们有着本质的区别。数组指针是指向一个完整数组的指针。

其定义语法为:数据类型 (*指针变量名)[数组长度] 。例如 int (*p)[5] ,表示指针 p 指向一个包含 5 个 int 类型元素的数组。

在处理一维数组时,我们可以这样使用数组指针。创建一个一维数组 int arr[] = {10,20,30,40,50} ,然后定义一个数组指针 int (*p)[len] = &arr (其中 len 是数组的长度)来指向该数组。通过数组指针遍历数组时,需要注意 * 和 [] 的优先级,[] 的优先级大于 * ,所以要用 (*p)[i] 的形式来访问数组元素。

对于二维数组,数组指针的使用更为常见。二维数组在内存中是按行连续存储的,数组名默认指向首行。我们可以用一维数组指针指向二维数组的行,例如 int (*p1)[3] = arr (其中 arr 是一个二维数组,每行有 3 个元素)。通过这种方式,我们可以灵活地访问二维数组中的元素,常见的访问方式有 p1[i][j] 、 (*(p1+i))[j] 、 *(p1[i]+j) 以及 *(*(p1+i)+j) 等。

指针数组

指针数组本质上是一个数组,只不过数组中的每个元素都是一个指针。

其定义语法为:数据类型 *数组名[数组容量] ,例如 int *arr[3] ,表示这是一个包含 3 个 int 类型指针的数组。

指针数组的特点是每个指针元素可以指向不同的内存地址,方便管理多个独立的指针。在处理字符串时,指针数组尤为实用,因为每个字符串在内存中是独立存储的,指针数组中的每个指针可以分别指向这些字符串。

比如,定义三个 int 类型变量 a = 10, b = 20, c = 30 ,然后创建指针数组 int *arr[3] = {&a, &b, &c} ,通过遍历该数组,使用 *arr[i] 就可以访问到对应的变量值。

数组指针与指针数组的区别

为了更清晰地区分数组指针和指针数组,我们可以从多个方面进行对比:

  • 定义:指针数组是数组元素均为指针的数组;数组指针是指向一个完整数组的指针。
  • 存储内容:指针数组存储多个指针,每个元素指向不同内存地址;数组指针存储单个指针,指向一个完整的数组(首地址)。
  • 内存分配:指针数组的每个指针元素独立分配内存,可能分散;数组指针指向的数组内存连续,指针本身存储数组首地址。
  • 语法示例:指针数组如 int *arr[5](元素为 5 个 int * 指针);数组指针如 int (*arr)[5](指向 5 个 int 的数组的指针)。
  • 访问方式:指针数组通过下标访问指针元素,再解引用:*arr[i];数组指针先解引用指针得到数组,再访问元素:(*arr)[i]。
  • 使用场景:指针数组用于管理多个独立指针(如字符串数组、动态结构体数组);数组指针用于操作多维数组(如传递二维数组的行指针)。

字符数组与字符指针

在 C 语言中,字符串的表示有两种方式:字符数组和字符指针。

字符数组是用数组来存放字符串,例如 char str[] = "I LOVE YOU" 。字符数组名是一个常量,不支持直接赋值,但可以通过 strcpy 函数来修改字符串内容。字符数组在内存中会开辟一块连续的空间来存放字符串中的每个字符,包括结束符 '\0' 。

字符指针是用指针指向一个字符串,例如 char *str = "I LOVE YOU" 。这里的指针 str 指向一个字符串常量,我们可以改变指针的指向,但不能修改字符串常量中的内容。

字符数组和字符指针既有联系也有区别。它们都能实现字符串的存储与运算,但字符数组由元素组成,每个元素存放一个字符;字符指针中存放的是地址。另外,只能对字符数组中的各个元素赋值,而不能用赋值语句对整个字符数组赋值,而字符指针可以初始化,也可以赋值改变指向。

当字符串作为函数参数时,实参与形参可以有多种组合。实参与形参都可以是字符数组;实参用字符数组,形参用字符指针;形参和实参都是字符指针(但在函数内部不能修改字符串常量中的字符);实参是字符指针,形参是字符数组(同样不能修改字符串常量中的字符)。

指针函数与函数指针

指针函数本质上是一个函数,其返回值类型是指针。它的定义语法有两种:

返回类型* 函数名(形参列表)

{

函数体;

return 指针;

}

或者

返回类型 *函数名(形参列表)

{

函数体;

return 指针;

}

需要注意的是,在函数中不要直接返回一个局部变量的地址,因为函数调用完毕后,局部变量的空间会被销毁,返回的地址就会变成野指针。如果非要返回,可以给局部变量添加 static 关键字,延长其生命周期,但这种方式尽量少用,可能会导致内存泄漏。

函数指针本质上是指针,它指向函数的入口地址。函数名就代表函数的入口地址。其定义语法为:返回类型 (*指针变量名)(形参列表) ,例如 int (*fun)(int a, int b) 。

函数指针的初始化可以在定义的同时赋值,也可以先定义后赋值。函数指针指向的函数要和函数指针定义的返回值类型、形参列表对应,否则会编译报错。函数指针不能进行指针运算,它可以作为形参,形成回调函数。

回调函数就是一个通过函数指针调用的函数。把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,就是回调函数。回调函数能把调用者与被调用者分开,使调用者不关心谁是被调用者,只需知道存在一个具有特定原型和限制条件的被调用函数。

二级指针

二级指针用于储存一级指针的地址,需要两次解引用才能访问原始数据。例如:

int a = 10;

int *p = &a;

int **w = &p;

这里 w 就是二级指针,通过 **w 可以访问到 a 的值。

二级指针与指针数组在某些时候存在等效性,例如可以用二级指针接收指针数组。但二级指针与二维数组不等效,二维数组名是数组指针类型,直接赋值给二级指针会导致类型不匹配。

总结

C 语言中的指针高级应用虽然复杂,但只要理清概念,结合实例多加练习,就能熟练掌握。数组指针、指针数组、字符数组与字符指针、指针函数、函数指针和二级指针各有其特点和用途,在实际编程中要根据具体需求灵活运用,以提高程序的效率和可读性。希望本文能帮助大家更好地理解和运用这些指针知识。

相关推荐
hhzz几秒前
Maven项目中settings.xml终极优化指南
java·jdk·maven
用户612041492213几秒前
C语言做的区块链模拟系统(极简版)
c语言·后端·敏捷开发
weixin_307779131 分钟前
C++进程监视器与自动启动程序
开发语言·c++·算法
草莓熊Lotso21 分钟前
【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day12
c语言·开发语言·c++·刷题
hqxstudying23 分钟前
MyBatis 和 MyBatis-Plus对比
java·数据库·mysql·mybatis
源码哥_博纳软云32 分钟前
JAVA国际版多商户运营版商城系统源码多商户社交电商系统源码支持Android+IOS+H5
android·java·ios·微信·微信小程序·小程序·uni-app
猿java43 分钟前
为什么复杂的架构一定要做分层设计?
java·面试·架构
whitepure1 小时前
万字详解常用数据结构(Java版)
java·数据结构·后端
天天摸鱼的java工程师1 小时前
你们公司的 QPS 是怎么统计出来的?这 5 种常见方法我踩过一半的坑
java·后端·面试
CoovallyAIHub1 小时前
目标检测模型评估金标准:mAP全解读,Coovally助你高效调参!
深度学习·算法·计算机视觉