函数指针数组指针数组传参的本质字符指针

news2024/11/28 12:44:26

🚀 作者:阿辉不一般
🚀 你说呢:不服输的你,他们拿什么赢
🚀 专栏:爱上C语言
🚀作图工具:draw.io(免费开源的作图网站)
请添加图片描述

如果觉得文章对你有帮助的话,还请点赞,关注,收藏支持博主,如有不足还请指点,博主及时改正,感谢大家支持!!!

文章目录

  • 🚀前言
  • 🚀字符指针变量
  • 🚀数组指针变量
  • 🚀数组传参的本质
    • ✈️一维数组传参的本质
    • ✈️二维数组传参的本质
    • 总结
  • 🚀函数指针变量
  • 🚀指针变量是什么?

🚀前言

在阿辉上一篇博客指针的基础篇中我们了解到指针的一些基础知识

  • 指针变量是用来存放地址的变量,通过指针可以找到所存地址指向的空间
  • 指针变量的大小与平台有关,64位/32位平台大小为8字节/4个字节
  • 指针变量的类型决定了指针变量所指向的内存空间的类型和大小以及指针加减整数时移动的字节数
  • 指针的运算
  • 多级指针

有了以上对于指针的基础了解,那么今天阿辉将为大家介绍C语言的指针部分,包括字符指针、数组指针、数组传参的本质以及函数指针,关注阿辉不迷路哦 😘 ,内容干货满满😋,接下来就跟着阿辉一起学习吧👊

🚀字符指针变量

在指针的类型中我们知道有⼀种指针类型为字符指针 char*
一般我们这么用:

int main()
{
 char ch = 'w';
 char *pc = &ch;
 *pc = 'w';
 return 0;
}

其实它还可以这么用:

int main()
{
 char* pstr = "hi bro";
 printf("%s\n", pstr);
 return 0;
}

可能大家认为ptr里面存的是hi bro,实际上ptr里面存的是字符串的首元素地址也就是h的地址,这里大家有没有发现其实这和字符数组是一样的,比如char arr[] = “hi bro”数组名arr 也是首元素h的地址,我们不妨把字符指针理解成字符数组,但真的这么简单吗?他们还是有两点不同,我们接着看👇
第一点不同:
在这里插入图片描述
我们可以看到当我们去改hi bro的内容时编译器直接报错,这是因为hi bro是常量字符串,而常量字符串被存储在程序的只读数据段(.rodata)中,这个数据段是只读的,意味着其中的数据在程序执行期间是不可修改的,而字符数组是可以修改的
第二点不同:

int main()
{
	char* str1 = "hi bro";
	char* str2 = "hi bro";
	char arr1[] = "hi bro";
	char arr2[] = "hi bro";
	if (str1 == str2)
		printf("str1与str2空间相同\n");
	else
		printf("str1与str2空间不相同\n");
	if(arr1 == arr2)
		printf("arr1与arr2空间相同\n");
	else
		printf("arr1与arr2空间不相同\n");

	return 0;
}

输出:

str1与str2空间相同
arr1与arr2空间不相同

其实很简单,这里str1str2指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以arr1arr2不同,str1str2相同

🚀数组指针变量

在之前阿辉的数组篇中讲到关于数组名的理解,数组名是数组首元素的地址,而取地址数组名是整个数组的地址,那取地址数组名既然是地址那它应该存在什么类型的指针中呢?没错,就是数组指针
例如:

	int arr[5] = { 0,1,2,3,4 };
	int(*p)[5] = &arr;
	p是变量名
	int(*)[5]是p变量的类型
	*指的是p是指针
	int[5]表示p指向的空间的类型是5int类型变量的数组
	[]的优先级高于*,所以要把*p用括号()括起来表明p是指针
	
	我们对p解引用,*p就是arr也就是首元素地址
	我们对*p再次解引用,就访问到数组第一个元素**p等价于arr[0]
	通过*(*p + i)我们就可以遍历数组arr[5]

那数组指针有何用?别急我们接着看👊

🚀数组传参的本质

✈️一维数组传参的本质

我们知道一维数组的数组名是首元素地址,当我们传一个数组给函数时,我们不会去在开辟一块同样的空间,而是通过首元素地址访问数组,这样有效的避免了空间的浪费
函数接收一维数组有三种方式,例如:

void test(int a[]);
void test(int a[5]);
void test(int* a);

写法确实有三种,不过前两种人模狗样的是数组(毕竟传数组用数组接受很容易理解)本质上还是指针,包括[5]这个5屁用没有
注意
我个人的一点总结:当一维数组名作为首元素地址传给函数后,函数内部接收地址的形参不再具有数组名的性质,仅仅是一个普通的指针
怎么理解呢,我们接着看👇

void test(int a[])
{
	&a;
	sizeof(a);
}
int main()
{
	int a[5] = { 1,2,3,4,5 };
	test(a);
	return 0;
}

在这里插入图片描述
上图是x86环境下的调试结果,我们看到&a类型是int * *是二级指针而并非数组指针,sizeof(a)的值是4,如果a还具有数组名的特性,我们知道&a将是int(*)[5]类型的数组指针,而sizeof(a)的值将是20。这恰恰说明了当一维数组名作为首元素地址传给函数后,函数内部接收地址的形参不再具有数组名的性质,仅仅是一个普通的指针

✈️二维数组传参的本质

void test(int arr[][4]);
void test(int arr[3][4]);
行可以省略,列不能省略

那函数接收二维数组还有没有其他的方式?
二维数组的数组名怎么理解呢?二维数组可以理解为数组的数组,二维数组的每一行理解为二维数组的一个元素,二维数组的数组名同样是首元素地址,只不过二维数组的首元素是第一行,比如下图中二维数组arr[3][4]首元素是绿色的那一行一维数组,所以二维数组的数组名arr表示一个int(*)[4]类型的数组指针

请添加图片描述
那么二维数组的传参就可以这么写void test(int (*arr)[4])
例子:

void test(int (*arr)[4])
{
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 4; j++)
		{
			printf("%d ", *(*(arr + i) + j));
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };
	test(arr);
	return 0;
}

在这里插入图片描述

总结

  • 一维数组的数组名是存放该数组首元素的一个指针,二维数组的数组名是存放该数组首元素的一个数组指针
  • 一个数组int arr[5]={1,2,3,4,5},你可以用arr[1]*(arr + 1)两种方式访问数组的了第二个元素,甚至可以1[arr]访问了解一下不建议使用。 *(arr+i)等价于arr[i]

🚀函数指针变量

函数指针变量顾名思义是存放函数地址的指针,函数也有地址吗?
没错函数也有地址,函数的函数名就是函数的地址
我们来看一段代码👇

#include <stdio.h>
void test()
{
 printf("hehe\n");
}
int main()
{
 printf("test: %p\n", test);
 printf("&test: %p\n", &test);
 return 0;
}

输出:

test:0xff44f68a
&test:0xff44f68a

我们看到test&test打印出来的地址是一样的,不仅打印出来的是一样的,它俩本质也是一样的,这俩等价,这个&多少有点多余 😆
那函数指针如何创建呢?其实与数组指针类似

int add(int x, int y)
{
	return x + y;
}

int main()
{
	int(*p)(int, int) = add;
		p是函数指针变量名
		*表示p是一个指针
		int(*)(int,int)是p的类型
		int(int,int)表示p所指向的空间是函数,函数的返回类型是int
		而且有两个int类型的形参
	return 0;
}

那函数指针变量有什么用呢?
我们可以通过函数指针变量来调用函数,用上面的函数演示

int ret = (*p)(3,5);
*P要用括号括起来,因为函数调用操作符的优先级更高

其实p*padd以及&add这四个等价
所以调用add这个函数(*p)(3,5)p(3,5)这俩都可以,取地址和解引用都挺多余😆

🚀指针变量是什么?

大家看到这个标题或许很懵,指针变量不就是用来存放地址的变量嘛,讲这么多了还问?

int add(int x, int y)
{
	return x + y;
}

int main()
{
	int(*padd)(int, int) = add;
	int a = 0;
	int* pa = &a;
	int arr[5] = { 1,2,3,4,5 };
	int(*parr)[5] = &arr;
	return 0;
}

上面这段代码中paddint( * )(in,int)类型的函数指针变量,paint类型的指针变量,parrint( * )[5]类型的数组指针变量,其实add也是 int( * )(in,int)类型的函数指针变量,&a也是int类型的指针变量,&arr也是int( * )[5]类型的数组指针变量

地址是类似于0xff40688a这样的玩意,add、&a、&arr里面存的不也是地址嘛,SO他们也是指针变量


到这里,阿辉今天对于C语言中一些特殊类型的指针的分享就结束了,希望这篇博客能让大家有所收获, 如果觉得阿辉写得不错的话,记得给个赞呗,你们的支持是我创作的最大动力🌹
请添加图片描述

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

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

相关文章

​ 云计算的尽头是轻量应用服务器?带你了解亚马逊Lightsail的卓越优势

很多小伙伴可能都在好奇&#xff0c;轻量应用服务器有什么特点&#xff1f;为什么相较于普通的云服务器&#xff0c;很多用户现在都更青睐于轻量应用服务器?这个“轻”就是它独特的优势所在。轻量应用服务器以其“开箱即用、应用优质、轻松上手、投入划算、运维便捷和稳定可靠…

最近得了一场病 差点要了我的命

最近得了一场病&#xff0c;前后持续了有十多天&#xff0c;时至今日感觉脑袋还是昏昏沉沉的不在状态&#xff0c;感觉像是药吃的&#xff0c;毕竟连着吃了十多天西药&#xff0c;可能人也吃傻了吧&#xff0c;中间还挂了五天水&#xff0c;算是补充了能量。 起因是和老婆去吃…

【Shell】Shell基础学习

一、shell脚本 (1)第一个shell脚本 #!/bin/bash #this is a comment echo "hello world"一个shell脚本永远以“#!”开头,这是一个脚本开始的标记,它是告诉系统执行这个文件需要用某个解释器,后面的/bin/bash就是指明解释器的具体位置。 “#”开头是注释 …

MBA-历年数学题

xx题 甲从1&#xff0c;2&#xff0c;3中抽取一数&#xff0c;记为α;乙从1&#xff0c;2&#xff0c;3&#xff0c;4中抽取一数&#xff0c;记为b规定当a>b或a1<b时甲获胜&#xff0c;则甲获胜的概率为&#xff1f; 倍数题 若实数a&#xff0c;b&#xff0c;c满足a∶b…

2024黑龙江省职业院校技能大赛暨国赛选拔赛“GZ034软件测试”赛项规程

2024黑龙江省职业院校技能大赛暨国赛选拔赛 “GZ034软件测试”赛项规程 一、赛项信息 赛项类别 每年赛 隔年赛&#xff08;单数年/双数年&#xff09; 赛项组别 中等职业教育 高等职业教育 学生赛&#xff08;个人/团体&#xff09; 教师赛 师生同赛 涉及专业大类、…

前缀和——1314. 矩阵区域和

文章目录 &#x1f3a4;1. 题目&#x1f3a4;2. 算法原理&#x1f3a4;3. 代码实现 &#x1f3a4;1. 题目 题目链接&#xff1a;1314. 矩阵区域和 - 力扣&#xff08;LeetCode&#xff09; 给你一个 m x n 的矩阵 mat 和一个整数 k &#xff0c;请你返回一个矩阵 answer &#…

easyExcel 注解开发 快速以及简单上手 以及包含工具类

easyExcel 简单快速使用 1. mevan 这里版本我这里选的是 poi 4.1.2和 ali的easyexcel 的 3.3.1。 因为阿里easy是根据poi的依赖开发的有关系&#xff0c;两者需要对应要不然就会有很多bug和错误在运行时发生。需要版本对应&#xff0c;然而就是easy的代码也会有bug这个版本是比…

【06】ES6:数组的扩展

一、扩展运算符 扩展运算符&#xff08;spread&#xff09;是三个点&#xff08;…&#xff09;。它是 rest 参数的逆运算&#xff0c;将一个数组转为用逗号分隔的参数序列。 1、基本语法 [...array] // array表示要转换的数组console.log(...[1, 2, 3]) // 1 2 3 console.l…

1233:单词倒置(C语言)

题目描述 最近birdfly收到了女友的几份信件&#xff0c;为了只要他俩知道信件的秘密&#xff0c;女友把信件里的每个单词都倒置了。这样只有birdfly将它们倒置过来才能明白女友的心思了。为此birdfly还特意请你编写程序帮他解决一下这个问题。 简单起见假定每封信只包含英文单词…

PC行内编辑

点击编辑&#xff0c;行内编辑输入框出现&#xff0c;给列表的每条数据定义编辑标记&#xff0c;最后一定记得 v-model双向绑定&#xff0c;使数据回显。 步骤&#xff1a; 1、给行数据定义编辑标记 2、点击行编辑标记&#xff08;isedit&#xff09; 3、插槽根据标记渲染表单 …

【ZYNQ】SD 卡读写及文件扫描实验

SD 卡控制器&#xff08;SD/SDIO Controller&#xff09; ZYNQ 中的 SD 卡控制器符合 SD2.0 协议规范&#xff0c;接口兼容 eMMC、MMC3.31、SDIO2.0、SD2.0、SPI&#xff0c;支持 SDHC、SDHS 器件。SD 卡控制器支持 SDMA&#xff08;单操作 DMA&#xff09;、ADMA1&#xff08…

【腾讯云云上实验室】用向量数据库——实现高效文本检索功能

文章目录 前言Tencent Cloud VectorDB 简介Tencent Cloud VectorDB 使用实战申请腾讯云向量数据库腾讯云向量数据库使用步骤腾讯云向量数据库实现文本检索 结论和建议 前言 想必各位开发者一定使用过关系型数据库MySQL去存储我们的项目的数据&#xff0c;也有部分人使用过非关…

vue3安装eslint和prettier,最简单的步骤

第1步&#xff1a; 安装eslint yarn add eslint -D 第2步&#xff1a; 在根文件夹中&#xff0c;创建.eslintrc.js文件 第3步&#xff1a; 在package.json文件中新增命令 "lint": "eslint --fix --ext .ts,.tsx,.vue src --quiet","prettier"…

编程学习及常见的技术难题

文章目录 编程学习及常见的技术难题引言如何学习编程学习参考开发工具推荐编程中常见的技术难题 编程学习及常见的技术难题 引言 学习编程是一件有趣也有挑战的事情&#xff0c;它可以让你创造出各种有用的软件&#xff0c;解决各种复杂的问题&#xff0c;甚至改变世界。 编程中…

数据结构与算法编程题30

层次遍历二叉树(队列&#xff1a;先进先出) #define _CRT_SECURE_NO_WARNINGS#include <iostream> using namespace std;typedef char ElemType; #define ERROR 0 #define OK 1 #define Maxsize 100 #define STR_SIZE 1024typedef struct BiTNode {ElemType data;BiTNode…

西南科技大学数字电子技术实验一(数字信号基本参数与逻辑门电路功能测试及FPGA 实现)FPGA部分

一、 实验目的 1、掌握基于 Verilog 语言的 diamond 工具设计全流程。 2、熟悉、应用 Verilog HDL 描述数字电路。 3、掌握 Verilog HDL 的组合和时序逻辑电路的设计方法。 4、掌握“小脚丫”开发板的使用方法。 二、 实验原理 与门逻辑表达式:Y=AB 原理仿真图: 2 输入…

Flask SocketIO 实现动态绘图

Flask-SocketIO 是基于 Flask 的一个扩展&#xff0c;用于简化在 Flask 应用中集成 WebSocket 功能。WebSocket 是一种在客户端和服务器之间实现实时双向通信的协议&#xff0c;常用于实现实时性要求较高的应用&#xff0c;如聊天应用、实时通知等&#xff0c;使得开发者可以更…

FreeRTOS源码阅读笔记6--event_groups.c

通常用的事件标志组是一个32位的变量uxEventBits&#xff0c;可设置的位有24位&#xff0c;一共就是24 种事件。 事件组的结构体类型&#xff1a; 6.1创建事件组xEventGroupCreate() 6.1.1函数原型 返回值&#xff1a;事件组句柄&#xff0c;指向事件组。 6.1.2函数框架 ①…

【牛客网】SQL必知必会题解

SQL 必知必会题解 地址&#xff1a;牛客网在线编程_SQL篇_SQL必知必会 (nowcoder.com) 检索数据 从 Customers 表中检索所有的 ID 现有表 Customers 如下&#xff1a; cust_idABC 【问题】编写 SQL 语句&#xff0c;从 Customers 表中检索所有的 cust_id 答案&#xff1a;…

HUAWEI WATCH 4系列腕上星球,智慧生活触手可得

腕上星球&#xff0c;智慧生活触手可得。HUAWEI WATCH 4系列星球表盘引领风潮&#xff0c;万能卡片轻松便捷开启应用&#xff0c;腕上微信聊天抬腕即回&#xff0c;更有超级快充助力畅玩。全能型智能手表&#xff0c;生活更出彩&#xff01;