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

C语言-指针(二)

一级指针

一级指针指的是存储变量地址指针

一级指针的变量类型是  类型 + *   

一级指针的类型与变量的类型有些不同

 例:int * p     前面的int * 是该地址的类型

int a = 0;
int * p = a;
这里的指针 p 就是一级指针

二级指针

指针变量也是变量因此也会有地址

而存储指针变量地址的指针称为二级指针

语法结构:指针类型    **     变量名       int ** pp = &p;

二级指针的类型是  类型 + **

例:int ** p     前面的int **  是该二级指针的类型

int a = 10;
int *p = &a;    // p 是一级指针,存储变量a的地址
int **pp = &p;  // pp 是二级指针,存储指针p的地址
// 通过 pp 修改 a 的值
**pp = 20;      // 等价于 *(*pp) = 20 → *p = 20 → a = 20

二级指针的变量名可以随意取,上述例子使用“ pp ”来表示,是一种命名习惯

并不表示二级指针的变量名要进行双写

指针形式得理解

int a = 10;    int *p = &a;  这里的int表示的是被取变量地址的类型是int*p ,前面的 * 表示的是p是一个指针变量
int * *pp = &p; int* 表示的是被取的一级指针的变量是int**pp 前面的 * 表示的是pp是一个指针变量

指针的套娃

一级指针到二级指针在形式上就是多加了一个 * 

在二级指针上在多加一个 * 就变成了三级指针,三级指针上在加一个 * 就变为四级以此类推,可以无限的套娃,但在平时使用中,二级指针已经满足使用要求,一般不使用三级以后的指针

一级指针二级指针的解引用

int a = 10;
int * p =&a;
int ** pp =&p;printf(“%p”,*pp);  这里使用解引用的个数决定了访问pp的那个地址的数据一个 * 表示访问的是二级指针 pp 的地址
printf(“%p”,**pp); 两个 * 表示访问的二级指针指向的一级指针的地址
printf(“%d”,**pp);   如果要访问一级指针的值则将前面的 %p 改为 %d

数组指针

数组指针的本质上还是数组,只是数组中存放的元素变成了指针

语法结构为:数据类型 * 数组名 [ 数组长度 ] ;

int *ptrArray[5];    // 声明一个包含5个int型指针的数组
char *strArray[3];   // 声明一个包含3个char型指针的数组

数组指针模拟二维数组

int arr1[] = {1,2,3,4,5};
int arr2[] = {2,3,4,5,6};int* parr[2] = {arr1, arr2};//数组指针存放的地址是数组首元素的地址模拟二维数组的访问
printf("%d",arr[i][j])
访问数组时,使用两个下标来确认访问那个数组,即该数组的两个元素
这里的arr[i][j] 等价于 *( *(arr+1)+j)
*( *(arr+i)+j)  中间的*(arr+1)表示的取下标为i的数组外层的*(   +j)表示的是取数组下标为j的元素
形式上虽然和二维数组相同,但本质上并不是二维数组
在运行时,是以指针的方式进行计算的在使用printf进行打印时,可以使用for循环进行遍历
将i,j的值进行循环即可将数组指针的所以值打印出来

字符指针变量

字符指针变量本质上是存放字符地址的指针

存储的是字符类型(char)数据的内存地址

字符指针变量存储的是字符串中第一个字符的地址

因为字符是连续存储的,所以可以通过运算符,下标来访问对应的字符

char ch = 'A';     // 定义一个字符变量
char *p = &ch;     // p存储ch的地址,即指向字符'A'
char *str = "Hello"; // str存储字符串"Hello"的首字符'H'的地址

数组指针变量

数组指针变量是用于存放数组地址的指针,指向的是数组的地址

语法结构:数据类型 (*指针名)[数组长度];

int (*p)[4];  // 定义一个指向包含4个int元素的数组的指针

数组指针初始化


二维数组的初始化无需使用&
int arr[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
int (*p)[4] = arr; // p指向二维数组的首元素,即二维数组中的第一行数组(arr=arr[0])
//输出
printf("%d\n", p[1][2]); // 输出 arr[1][2] 的值(7)
一维数组的初始化必须使用&
int row[4] = {100, 200, 300, 400};
int (*p)[4] = &row; //使用&来获取一维数组的地址
//输出
printf("%d\n", (*p)[2]); // 输出 row[2](300)

二维数组传参的本质

二维数组传参的本质是通过数组指针传递并计算内存地址

当二维数组作为参数传递给函数时,数组名会退化为指向其首行的数组指针

传递的是二维数组中第一行的数组的指针的地址,而非单个元素的指针

二维数组的所有操作本质上都可以通过数组指针来理解(并不是只要传参才通过数组指针来进行的)

int arr[3][4] = {...};
void func(int (*p)[4], int rows);    参数p是数组指针
func(arr, 3);   arr退化为 int(*)[4] 类型的指针将数组名去掉剩下的就是指针的类型

函数指针变量

用于存储函数的地址,允许通过指针间接调用函数

语法结构:函数的返回类型 ( * 指针名)(参数类型1,参数类型2);

int add (int a,int b)
{int c = a + b;return c;
}
int (*pf)(int, int); 指向函数的参数是两个int类型pf在命名习惯上表示存放函数的地址

使用函数指针调用函数

语法结构:( * 指针名)(参数类型1,参数类型2);

int result = pf(3, 4);      利用函数名调用函数int result = (*pf)(3, 4);   利用函数指针调用函数
(*pf)等价于pf , (3,4)表示的是给函数传递的参数

typedef关键字

用于为已有的数据类型定义新的名称(别名)

它的核心目的是简化复杂类型的声明,提高代码的可读性和可维护性

语法结构:typedef 原类型 新类型名;

typedef int Integer;      // 将 int 重命名为 Integer
Integer a = 10;          // 等价于 int a = 10;
指针类型                 //此时的Integer表示为int
typedef int * pf;
pf a ;           //等价于int * a;
数组指针
typedef int(*pf)[5];   //取得别名要放在数组名的位置上,不能放在末尾
函数指针
typedef void(*pf)(int);//函数指针与数组指针同理//取得别名要放在数组名的位置上,不能放在末尾

typedef 与 #define 的区别

在声明指针时

typedef int* IntPtr;
IntPtr a, b;  // a 和 b 均为 int* 类型#define IntPtr int*  //仅第一个变量被替换为指针,第二个为int
IntPtr a, b;  // 展开为 int* a, b; → a 是 int*,b 是 int(错误!)
因为#define的底层机制是单纯的文本替换,不具有任何的类型类型逻辑
替换后的代码中,* 仅作用于紧邻的变量,导致多个变量声明时类型不一致
特性typedef#define
处理阶段编译时类型处理预处理时文本替换
作用域受限于块作用域全局替换,无作用域限制
类型安全性严格类型检查无类型检查,可能引入错误
适用场景类型别名宏定义、常量、代码片段替换

函数指针数组

将多个函数的地址存入数组中,那么这个数组称为函数指针数组

只有函数指针类型都相同的函数才能将他们的地址存放到同一个函数指针数组中

语法结构:返回类型 ( * 数组名 [ 数组长度 ] ) ( 参数类型1,参数类型2 ) ;

声明
int (*pf[3])(int, int);定义
int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);// 初始化函数指针数组
int (*funcArray[3])(int, int) = {add, sub, mul};

相关文章:

  • libevent库详解:高性能异步IO的利器
  • 【数据结构】单链表的增删查改
  • 使用AI-01开发板和开源后端服务搭建整套小智服务系统
  • Encoder-free无编码器多模态大模型EVEv2模型架构、训练方法浅尝
  • 读书记:《认知红利》
  • 【计算机网络网络层深度解析】从IP协议到路由优化
  • 第二届平航杯wp
  • 深度学习笔记40_中文文本分类-Pytorch实现
  • 数字智慧方案6189丨智慧应急综合解决方案(46页PPT)(文末有下载方式)
  • n8n 使用 AI Agent 和 MCP 社区节点
  • 树与二叉树完全解析:从基础到应用
  • 4.27-5.4学习周报
  • 如何实现服务的自动扩缩容(Auto Scaling)
  • 1️⃣7️⃣three.js_OrbitControls相机控制器
  • 溯因推理思维——AI与思维模型【92】
  • 【免费】2007-2021年上市公司对外投资数据
  • 数字世界的“私人车道“:网络切片如何用Python搭建专属通信高速路?
  • P2196 [NOIP 1996 提高组] 挖地雷
  • Python爬虫基础总结
  • 【算法】动态规划专题一 斐波那契数列模型 1-4
  • 巴菲特批评贸易保护主义:贸易不该被当成武器来使用
  • 特朗普宣布提名迈克·沃尔兹为下一任美国驻联合国大使
  • 5月人文社科中文原创好书榜|巫蛊:中国文化的历史暗流
  • 西湖大学2025年上海市综合评价招生简章发布
  • 解放日报:上海深化改革开放,系统集成创新局
  • 浦发银行一季度净利175.98亿增1.02%,不良率微降