一篇文章了解区分指针数组,数组指针,函数指针,链表。

news2024/9/8 23:08:51

最近在学习指针,发现指针有这许多的知识,其中的奥妙还很多,需要学习的也很多,今天那我就将标题中的有关指针知识,即指针数组数组指针函数指针,给捋清楚这些知识点,区分这些名词,望各位能赏眼观看一下,如有不足,还请指点。下面就开始敲下这篇文章了。

目录

指针数组

 数组指针

函数指针

链表


指针数组

指针数组,那么何为指针数组?仅仅看这个名词,各位觉得它是数组还是指针变量呢?那我们先来看一下官方的解释,何为指针数组。 

在 C 语言中,指针数组是一种特殊的数据结构,它是一个数组,其中每个元素都是一个指针。
 

指针数组的定义方式如下:
 
类型 *数组名[数组大小];
 
 
其中, 类型  是指针所指向的元素的类型, 数组名  是指针数组的名称, 数组大小  表示指针数组的大小。
 
例如,以下代码定义了一个整数指针数组:
 
 

int *ptrArray[10];


 
这个指针数组  ptrArray  可以存储 10 个指向整数的指针。
 
指针数组的成员可以像普通指针一样进行操作,可以通过指针间接访问所指向的元素。例如:
 

int num = 10;
ptrArray[0] = #


 
 
上述代码将整数变量  num  的地址赋值给指针数组  ptrArray  的第一个元素。
 

需要注意的是,指针数组中的每个指针都需要单独进行内存分配和释放,确保在使用指针数组时正确管理内存。

指针数组的概念我们已经了解得差不多了,那么我们也实际运用一下指针数组吧!

运用指针数组来模拟出一个二维数组

相信各位那么聪明也是很快就想出怎么敲出这个简单的代码了吧。下面展示本人的代码。如下:

int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[5] = { 11,22,33,44,55 };
	int arr3[5] = { 6,7,8,9,10 };

	int* p[3] = { &arr1,&arr2,&arr3 };

	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d ", p[i][j]);
		}
		printf("\n");
	}





	return 0;
}


根据运行结果来看,代码是完美的运行成功了。

需要注意的是:这里虽然是好像 *p[ 3] 确实可以完成一个二维数组的功能,但也是和真正的二维数组有所区别的,二维数组中的相邻元素中的地址也是连续的,而用指针数组模拟出来的每个元素地址,并不是连续的。大家可看下下面的图。

很明显3个数组的地址是不连续的,故里面的元素地址肯定也不是连续的。


 数组指针

数组指针,咋一看怎么和刚刚说的指针数组那么像呢?那数组指针是指针还是数组呢?老样子我们看看官方的回答。

在 C 语言中,数组指针是一个指向数组的指针。它用于通过指针访问和操作数组中的元素。
 
数组指针的定义方式如下:
 
 
类型 (*指针名)[数组大小];
 
 
其中, 类型  是数组元素的类型, 指针名  是数组指针的名称, 数组大小  表示数组的大小。
 
例如,以下代码定义了一个整数数组指针:
 
 

int (*ptrArray)[10];


 
 
这个数组指针  ptrArray  可以指向一个包含 10 个整数元素的数组。
 
使用数组指针,可以通过指针间接访问和操作数组中的元素。例如:
 
 

int arr[10] = {0};
ptrArray = &arr;
 


 
上述代码将整数数组  arr  的地址赋值给数组指针  ptrArray ,使得  ptrArray  指向  arr  数组。
 

通过  ptrArray  可以访问和操作  arr  数组中的元素,如下所示:
 
 

printf("%d\n", *ptrArray[0]);
 


 
上述代码使用间接寻址运算符  *  来访问数组指针  ptrArray  所指向的数组的第一个元素。
 

需要注意的是,在使用数组指针时,要确保指针所指向的数组的边界和指针的类型匹配,以避免越界访问和错误。
 
 


看完大家是不是又对这个知识有了更加透彻的理解了呢?

那看完了我们也用数组指针来实践应用到代码当中!

二维数组传参,数组指针来接收

在实践之前我们首先要知道一个知识点,我上篇文章说过,传参时如果用数组名进行传参,传过去的是数组的首元素大小,那么我们知道一维数组的首元素为数组的第一个值,那么二维数组呢?也是第一行第一个数吗?事实上二维数组的首元素其实是第一行,注意这里说的是整整一行,而不是一个,那么怎么证明呢?继续往下看。


#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int arr[3][4] = { {1,2,3,4},{11,22,33,44},{7,8,9,10} };
	
	printf("%d\n", sizeof(*arr));         //首元素大小,也就是第一行元素的大小
	printf("%d\n", sizeof(*(arr+1)));           //第二行元素的大小
	
	return 0;
}

从结果上不难发现这里 显示的16,正是第一行的4个元素的大小。故其实二维数组的首元素为数组的第一行。

那么知道这个知识点之后我们就可以开始完成上面说的实际应用了,二维数组传参,数组指针来接收 。因为传的是第一行,那么我们不妨就用数组指针来接收。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

void Print(int(*p)[4], int x, int y)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < x; i++)
	{
		for (j = 0; j < y; j++)
		{
			printf("%d ",(*(*(p + i) + j)));
		}
		printf("\n");
	}




}



int main()
{
	int arr[3][4] = { {1,2,3,4},{11,22,33,44},{7,8,9,10} };
	Print(arr, 3, 4);
	
	return 0;
}

在这串代码中,我们通过数组名将arr数组的首元素传到函数Print中,用数组指针p来接收,最后完成数组打印。

到这里我们先来一个小总结:指针数组就是存着指针的数组数组指针就是指向数组的指针,我们只需要抓住后面的名词即可区分住指针数组数组指针了。 


函数指针

”函数指针“,当初我刚学的时候也在想函数也有指针吗?直到学到这个知识点才逐渐明白。

那么什么是函数指针呢?老样子我们看一下官方的解释。

在 C 语言中,函数指针是一个指向函数的指针。它用于通过指针调用函数。
 
函数指针的定义方式如下:
 
 
返回值类型 (*函数指针名)(参数列表);
 
 
其中, 返回值类型  是函数返回值的类型, 函数指针名  是函数指针的名称, 参数列表  是函数的参数列表。
 
例如,以下代码定义了一个指向整数函数的指针:
 
 

int (*funcPtr)(int, int);


 
 
这个函数指针  funcPtr  可以指向一个返回整数并接受两个整数参数的函数。
 
使用函数指针,可以通过指针调用所指向的函数。例如:
 
 

int add(int a, int b)
{
    return a + b;
}

funcPtr = add;
 


 
上述代码将函数  add  的地址赋值给函数指针  funcPtr 使得  funcPtr  指向  add  函数。
 
然后,可以使用  funcPtr  来调用  add  函数,如下所示:
 
 

int result = funcPtr(3, 4);


 
 
上述代码通过函数指针  funcPtr  调用了  add  函数,并将结果存储在变量  result  中。
 
使用函数指针可以实现函数的动态调用,使代码更加灵活和可复用。


看完上面的内容,相信各位对函数指针也有所了解了。

那我们在深入一点,回想当初我们调用函数时所用的都是数组名进行调用,那么这里我们就要思考一下了,函数的数组名是什么呢?

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

int Add(int a, int b)
{

	return a + b;
}





int main()
{

	int (*p)(int, int) = &Add;
	printf("%p\n", p);
	printf("%p\n", Add);

	int c=(*p)(3, 4);
	int d = p(3, 4);
	int f = Add(3, 4);

	printf("c=%d\n", c);
	printf("d=%d\n", d);
	printf("f=%d\n", f);


	return 0;
}


 

观察上面代码,是否发现数组名Add和指针p打印出来都是同一个地址,说明其实数组名也是一个地址,而且我上面的代码运用了三种方法去调用这个函数,可以发现调用时即使是指针也不一定要用”*“。

了解完后想必大家都在想那函数指针有什么用呢?数组名就可以调用函数了,要指针来干嘛。这个就要涉及到链表函数回调了。


链表

 链表的话我们可以简单理解为函数指针数组,咋一听是不是又发现了一个新名词了。其实它也不是很难,可以参考指针数组,函数指针数组多了两字,也就是储存函数指针的数组,这么一听是不是又对它明了许多呢。

函数指针数组定义如下:

返回值类型 (*函数指针名)[数组个数](参数列表);

举例如下:

int (*p)[10](int ,int)

下面是一个用链表的应用完成一个计算器功能:

#include <stdio.h>
int Add(int a, int b)
{
	return a + b;
}
int Sub(int a, int b)
{
	return a - b;
}
int Mul(int a, int b)
{
	return a * b;
}
int Div(int a, int b)
{
	return a / b;
}
int main()
{
	int x, y;
	int input = 1;
	int ret = 0;
	int(*p[5])(int x, int y) = { 0, Add, Sub, Mul, Div };
	do
	{
		printf("*************************\n");
		printf(" 1:加法   2:减法 \n");
		printf(" 3:乘法   4:除法 \n");
		printf(" 0:退出 \n");
		printf("*************************\n");
		printf("请选择你所需的功能:");
		scanf("%d", &input);
		if ((input <= 4 && input >= 1))
		{
			printf("输⼊操作数:");
			scanf("%d %d", &x, &y);
			ret = (*p[input])(x, y);
			printf("ret = %d\n", ret);
		}
		else if (input == 0)
		{
			printf("退出计算器\n");
		}
		else
		{
			printf("输⼊有误\n");
		}

	} while (input);
	return 0;
}

上面我们将运算的加减乘除函数写出来后,利用函数指针数组将其储存起来,然后根据用户选择的选项调用其数组的元素,也就是加减乘除的函数,最后通过指针进行调用,完成功能。

这就是函数指针的实践运用了。至于函数回调,就要留到下一篇指针文章了。敬请期待哦!

文章已到末尾,望各位多多支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1432001.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux取经路】进程控制——程序替换

文章目录 一、单进程版程序替换看现象二、程序替换的基本原理三、程序替换接口学习3.1 替换自己写的可执行程序3.2 第三个参数 envp 验证四、结语一、单进程版程序替换看现象 #include <stdio.h> #

【Funny guys】龙年专属测试鼠标寿命小游戏...... 用Python给大家半年了......

目录 【Funny guys】龙年专属测试鼠标寿命小游戏...... 用Python给大家半年了...... 龙年专属测试鼠标寿命小游戏用Python给大家半年了贪吃龙游戏 文章所属专区 码农新闻 欢迎各位编程大佬&#xff0c;技术达人&#xff0c;以及对编程充满热情的朋友们&#xff0c;来到我们的程…

Spring Boot + flowable 快速实现工作流

背景 使用flowable自带的flowable-ui制作流程图 使用springboot开发流程使用的接口完成流程的业务功能 文章来源&#xff1a;https://blog.csdn.net/zhan107876/article/details/120815560 一、flowable-ui部署运行 flowable-6.6.0 运行 官方demo 参考文档&#xff1a; htt…

SpringBoot整合Flowable最新教程(二)启动流程

介绍 文章主要从SpringBoot整合Flowable讲起&#xff0c;关于Flowable是什么&#xff1f;数据库表解读以及操作的Service请查看SpringBoot整合Flowable最新教程&#xff08;一&#xff09;&#xff1b;   其他说明&#xff1a;Springboot版本是2.6.13&#xff0c;java版本是1…

4. 树(二叉树、二叉查找树/二叉排序树/二叉搜索树、平衡二叉树、平衡二叉B树/红黑树)

树 1. 二叉树1.1 概述1.2 特点1.3 二叉树遍历方式1.3.1 前序遍历(先序遍历)1.3.2 中序遍历1.3.3 后序遍历1.3.4 层序遍历 2. 二叉查找树&#xff08;二叉排序树、二叉搜索树&#xff09;2.1 概述2.2 特点 3. 平衡二叉树3.1 概述3.2 特点3.3 旋转3.3.1 左旋3.3.2 右旋 3.4 平衡二…

指针的学习2

目录 数组名的理解 使用指针访问数组 一维数组传参的本质 冒泡排序 二级指针 指针数组 指针数组模拟二维数组 数组名的理解 数组名是数组首元素的地址 例外&#xff1a; sizeof(数组名),sizeof中单独放数组名&#xff0c;这里的数组名表示整个数组&#xff0c;计算的…

EasyCVR智能视频监控平台云台降低延迟小tips

TSINGSEE青犀视频监控汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力&…

彻底学会系列:一、机器学习之线性回归

1.基本概念 线性回归&#xff1a; 有监督学习的一种算法。主要关注多个因变量和一个目标变量之间的关系。 因变量&#xff1a; 影响目标变量的因素&#xff1a; X 1 , X 2 . . . X_1, X_2... X1​,X2​... &#xff0c;连续值或离散值。 目标变量&#xff1a; 需要预测的值: t…

智慧未来已至:人工智能与数字孪生共筑城市新纪元

随着科技的飞速发展&#xff0c;人工智能与数字孪生技术正逐步成为智慧城市建设的核心驱动力。 这两项技术的结合&#xff0c;不仅将彻底改变城市的传统面貌&#xff0c;更将引领我们走向一个更加高效、便捷、绿色的未来。 一、智慧城市的新内涵 智慧城市&#xff0c;是指在城…

DDoS攻击:分布式拒绝服务攻击的威胁与对策

DDoS攻击&#xff1a;分布式拒绝服务攻击的威胁与对策 随着互联网的快速发展&#xff0c;网络安全威胁也在不断增加。其中&#xff0c;分布式拒绝服务攻击&#xff08;DDoS&#xff09;是一种常见且具有破坏性的攻击方式&#xff0c;给个人用户、企业和组织的网络基础设施带来了…

爬虫工作量由小到大的思维转变---<第四十五章 Scrapyd 关于gerapy遇到问题>

前言: 本章主要是解决一些gerapy遇到的问题,会持续更新这篇! 正文: 问题1: 1400 - build.py - gerapy.server.core.build - 78 - build - error occurred (1, [E:\\项目文件名\\venv\\Scripts\\python.exe, setup.py, clean, -a, bdist_uberegg, -d, C:\\Users\\Administrat…

React进阶 - 15(React 中 ref 的使用)

本章内容 目录 一、e.target 获取事件对应“元素”的DOM节点二、ref三、ref 和 setState 合用 上一节我们了解了 React中的”虚拟DOM“中的”Diff算法““ &#xff0c;本节我们来说一说 React中 ref的使用 一、e.target 获取事件对应“元素”的DOM节点 打开之前工程中的 To…

elasticsearch重置密码操作

安装es的时候需要测试这个url&#xff1a;http://127.0.0.1:9200/ 出现弹窗让我输入账号和密码。我第一次登录&#xff0c;没有设置过账号和密码&#xff0c; 解决方法是&#xff1a;在es的bin目录下打开cmd窗口&#xff0c;敲命令&#xff1a;.\elasticsearch-reset-password…

给mysql设置时区

每次重启MySQL服务器后&#xff0c;使用IDEA的database navigator连接都会出现这种情况 解决方式就是 命令行登录后 set global time_zone 8:00;嘿嘿把之前自家简书文章 给mysql设置时区 搬运过来了&#xff0c;方便查阅

Zookeeper相关面试准备问题

Zookeeper介绍 Zookeeper从设计模式角度来理解&#xff0c;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理大家都关心的数据&#xff0c;然后接受观察者的注册&#xff0c;一旦这些数据的状态发生了变化&#xff0c;Zookeeper就负责通知已经在Zoo…

【lesson37】自己设计用户级缓冲区

文章目录 自己设计用户级缓冲区简易MyFILE_的结构fopen_的实现fputs_的实现fclose_的实现fflush_的实现 完整版代码 自己设计用户级缓冲区 因为用户缓冲区在FILE中&#xff0c;所以我们直接模仿C语言提供的文件操作接口&#xff0c;顺便实现缓冲区。 使用文件系统的框架&#…

C++ 图(三十八)【第四篇】

接下来&#xff0c;我们先学习一个概念&#xff0c;带有权值的图&#xff0c;其实就是每条边上有一个自己独立的值了&#xff0c;接下来我们来进行一个深入的了解吧。 1.带权值得的图的概念 在前面的课程中&#xff0c;图中的边都只是用来表示两个点之间是否存在关系&#xff…

SQL注入其他方法

此次实验因为环境问题很多无法复现&#xff0c;在此只讨论过程和方法 一、SQL注入之outfile注入 mysql的outfile的作用是导出文件&#xff0c;使用此方法的必要条件&#xff1a;&#xff08;此方法成功率极低&#xff09; 1、知道目标网站的物理路径&#xff1b; 2、%secur…

Python算法题集_螺旋矩阵

Python算法题集_螺旋矩阵 题目54&#xff1a;螺旋矩阵1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【检测4个方向】2) 改进版一【检测2个方向】3) 改进版二【可读性改进】 4. 最优算法 题目54&#xff1a;螺旋矩阵 本文为Python算法题集之一…

《Pandas 简易速速上手小册》第9章:Pandas 数据可视化(2024 最新版)

文章目录 9.1 Pandas 内置可视化工具9.1.1 基础知识9.1.2 重点案例&#xff1a;销售数据分析9.1.3 拓展案例一&#xff1a;产品评价统计9.1.4 拓展案例二&#xff1a;员工满意度分布 9.2 与 Matplotlib 和 Seaborn 集成9.2.1 基础知识9.2.2 重点案例&#xff1a;销售趋势分析9.…