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

深入理解指针(6)

760a3ccb5d6a454e9d94b75eb315cac2.png

目录:

1.字符指针变量

2.数组指针变量

3.二维数组传参本质

4.函数指针变量

5.函数指针的应用


1.字符指针变量

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int main()
{
	char a = 'w';
	char* p = &a;
	printf("%p ", p);

}

当我们想取出字符的地址时,我们可以这样写,这是很简单的

但是字符串的地址呢?

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int main()
{
	const char* p = "abcd";
	printf("%p \n", p);
	//打印出地址
	printf("%s \n", p);
	//打印出abcd
}

这里是把整个字符串的地址放进指针P中了吗?

不是的,其实这只是存入了字符串首元素的地址,但是整个字符串都被打印出来了,这是因为当我们使用这个地址打印时,编程软件会从这个地址开始顺藤摸瓜,直接摸索完整个字符串

也就是说会从a的地址所指向的元素开始打印,顺藤摸瓜到 '\0'

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int main()
{
	const char* p = "abcd";
	printf("%p \n", p);
	//打印出地址
	printf("%s \n", p+1);
	//打印出bcd
}

把地址+1后,地址跳到b的地址,就会从b开始顺藤摸瓜到 '\0' 


关于这里解引用的疑惑:

我们在用地址打印字符串时不该使用解引用,因为我们只可以存入字符串首元素的地址,一旦解引用后就会只打印一个字符,并不会打印出字符串,例如:

(字符串的地址不解引用时,电脑自己就会顺着这个地址顺藤摸瓜出所有字符,直到'\0'停止)

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int main()
{
	const char* p = "abcd";
	printf("%c \n", *p);
	//打印字符'a'
}

练习题


#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int main()
{
	char str1[] = "hello world";
	char str2[] = "hello world";
	const char* str3 = "hello world";
	const char* str4 = "hello world";
	if (str1 == str2) {
		printf("str1 and str2 are same\n");
	}
	else {
		printf("str1 and str2 are not same\n");
	}

	if (str3 == str4) {
		printf("str3 and str4 are same\n");
	}
	else {
		printf("str3 and str4 are not same\n");
	}
}

结果:str1 不等于 str2,str3 等于 str4

这是因为当我们利用数组时,数组就会开拓出新的内存空间,所以即使我们利用数组存入是一样的内容,但是内存的位置不一样

但是当我们将数据存入地址后,系统会判定,我们存入了这样的东西,这样当我们想再次使用时,就会利用之前地址存入的元素,不会创建新的空间


2.数组指针变量

我们学习过了指针数组,它是专门存放地址的数组,那数组指针又是什么呢?
我们知道,整型指针是存放整型地址的指针变量

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

那数组地址就是存放数组地址的指针变量

代码写法如下:

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3 };
	int (*p)[3] = &arr;//数组指针 p
	//注意事项:
	//不可以写 int * p [3]
	//不可以写 int (*p)[ ]
}

这里的 (*p) 一定要括在一起让它们相连才是数组指针

我们知道指针数组的写法,int * arr[3],这是一个指针数组,如果我们不让 (*p) 连在一切,int *就会优先连在一起,变为int *类型的变量,也就是会变成指针数组

所以我们要写(*p),表示p是一个指针

(*p)说明p是一个指针变量,int 说明这个数组地址的类型是 int

[3]是在因为arr的类型是int [3](方便以后顺藤摸瓜)


3.二维数组传参本质

我们上节课讲到,二维数组的首元素是第一行一维数组的地址,那二维数组传参传过去的也是吗?

51c9cd5bfc944e5997f70bfb0755ff6d.png

我们会发现,确实,二维数组传参也根据数组名的法则,数组名表示首元素地址,只不过二维数组的首元素地址是第一行一维数组的地址

要注意,传参传过去的是整个一维数组的地址,既然是整个数组的地址,就要用数组指针来接收,所以在函数接收处写的是

void bk(int(*p)[3]) 

4.函数指针变量

函数指针变量其实就是函数指针,即存放函数地址的指针变量

1ce2d863f38c4e6faf67f821e4f51f1d.png

我们会发现,无论是直接用函数名还是取出函数的地址,打印出来的结果都是一样的

所以函数也是有地址的,函数名就是函数的地址


那我们该如何存放函数的地址呢?

其实与数组指针相似

例如:

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int bk(int* a) {
	//printf("%p\n", p);
	return 0;
}
int main()
{
	int a = 10;
	bk(&a);
	int (*p)(int* a) = bk;
	//把bk的地址存入p中
	printf("%p\n", p);
	//打印出bk的地址
	printf("%p\n", bk);
	//打印出bk的地址
}

(*p)是在说明p是一个指针变量,int 说明 函数返回的类型是int ,函数指针中(int *a)说明函数bk的参数类型是int *a ,即函数参数写什么函数指针那里就写什么


5.函数指针的应用

我们知道函数指针存放的是函数的地址,函数名又本身就是函数的地址

我们在使用函数时通常这么写

Add(a,b);

如果Add的地址存放进函数指针中,那用函数指针岂不是一样的

88193518d42247caad45b24b5a862982.png

我们看到,结果确实正确

c7347edbb2eb458fb0f694ea4f0d98cb.png


http://www.kler.cn/a/286512.html

相关文章:

  • 《一文读懂!Q-learning状态-动作值函数的直观理解》
  • 关于el-table翻页后序号列递增的组件封装
  • openeuler 22.03 lts sp4 使用 cri-o 和 静态 pod 的方式部署 k8s-v1.32.0 高可用集群
  • 5分钟带你获取deepseek api并搭建简易问答应用
  • python——Django 框架
  • 【ESP32】ESP-IDF开发 | WiFi开发 | UDP用户数据报协议 + UDP客户端和服务器例程
  • 计算机毕业设计Hadoop+Spark抖音可视化 抖音舆情监测 预测算法 抖音爬虫 抖音大数据 情感分析 NLP 自然语言处理 Hive 机器学习 深度学习
  • QIIME2宏基因组学教程--2024年春季莱顿和苏黎世教程
  • oracle物理存储结构文件详解
  • 【Tools】二叉树先序遍历
  • 网闸与防火墙的区别
  • js生成唯一标识符(例如key或者id)
  • linux小程序-进度条
  • 【iOS】如何制作苹果开发者证书、p12文件全流程(图文详情)
  • Python标准库学习之platform模块
  • macos USB外接键盘ctrl键绑定方法 解决外接USB键盘与mac键盘不一致问题
  • SpringSecurity Oauth2 - 密码认证获取访问令牌源码分析
  • gNB UE发送Timing AdvanceCommand
  • 新手如何学单片机
  • 续:MySQL的gtid模式
  • Nginx: TCP建立连接的优化和启用Fast Open功能
  • unicode编码存在转义字符,导致乱码问题的解决方案
  • 在gitignore忽略目录及该目录下的子文件
  • Guava Cache实现原理及最佳实践
  • 全国大学生数据建模比赛——深度学习
  • 网络工程师学习笔记——局域网和城域网