C语言之指针的奥秘(三)

news2024/9/20 20:25:00

一、字符指针变量

在指针的类型中,有字符指针char*,一般使用:

#include<stdio.h>
int main()
{
	char ch = 'w';
	char* p = &ch;
	*p = 'w';
	return 0;
}

还有一种方式:

#include<stdio.h>
int main()
{
	const char* p = "hello world";
	printf("%s\n", p);
	return 0;
}

 这个代码的本质是把字符串hello world首字符的地址放到p中,即把一个常量字符串的首字符h的地址存放到指针变量p中。

const可去掉,加上const效果更好

 学习一道和字符串相关的题:

#include<stdio.h>
int main()
{
	char str1[] = "hello bit.";
	char str2[] = "hello bit.";
	const char* str3 = "hello bit.";
	const char* str4 = "hello bit.";
	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");

	return 0;
}

思考一下运行结果是什么呢?

这里str3和str4指向的是同一个常量字符串,指向的都是“”hello bit.的地址。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串时,他们会指向同一块内存。但是用相同的常量字符串去初始化不同的数组时就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。

相同的常量字符串没必要保存多份,因为常量字符串不能被修改,所以大家共用一份是能满足需要的,这样也能节省空间!

二、数组指针变量

1.数组指针变量的概念

整型指针变量:存放的是整型变量的地址,能够指向整型数据的指针。

浮点型指针变量:存放的是浮点型变量的地址,能够指向浮点型数据的指针。

数组指针变量:存放的是数组的地址,能够指向数组的指针变量。

int *p1[10];
int (*p2)[10];

 p1是指针数组,存放指针的数组;

p2是数组指针,p2先和*结合,说明p2是一个指针变量,然后指针指向的是一个大小为10个整型的数组,所以p2是一个指针,指向数组,叫做数组指针

注意:[ ]的优先级要高于*,所以必须加上( )来保证p先和*结合。

2.数组指针变量初始化

 数组指针类型解析:去掉名字就是,剩下的就是数组指针类型,即int (*)[10] 

三、二维数组传参的本质

若有一个二维数组需要传参给一个函数时,过去会这样写:

#include<stdio.h>
void Print(int arr[3][5], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	Print(arr, 3, 5);
	return 0;
}

还有其它写法吗?

二维数组启示可以看作是一维数组的数组,也就是二维数组的每个元素是一个一维数组,那么二维数组的首元素就是第一行,是个一维数组。

根据数组名是数组首元素的地址这个规则,二维数组的数组名就是第一行的地址,是一维数组的地址。由上图可得,第一行的一维数组类型是int [5],所以第一行的地址的类型就是数组指针类型int (*) [5]。

二维数组传参本质上是传递了地址,传递的是第一行这个一维数组的地址。

 若有一个二维数组需要传参给一个函数时,还可以写成指针形式:

#include<stdio.h>
void Print(int(*p)[5], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{
			printf("%d ", *(*(p + i) + j));
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	Print(arr, 3, 5);
	return 0;
}

二维数组传参,形参的部分可以写成数组,也可以写成指针形式。

四、函数指针变量

1.函数指针变量的创建

函数指针变量是用来存放函数地址的,通过地址能调用函数。

先看一段代码:

我们可以看到运行结果是一样的。我们可以得到:函数是有地址的, 函数名就是函数的地址,也可以通过&函数名的方法获得函数的地址。

如果要将函数的地址存放起来,就要创建函数指针变量:

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int(*pf1)(int, int) = Add;
	int(*pf2)(int x, int y) = &Add;
	return 0;
}

函数指针类型:int  (*)  (int  x,int  y) 

2.函数指针变量的使用

通过函数指针调用函数指针指向的函数。

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int a = Add(2, 3);
	printf("%d\n", a);

	int (*pf)(int, int) = Add;
	int b = (*pf)(2, 3);
	printf("%d\n", b);
	int c = pf(2, 3);
	printf("%d\n", c);
	return 0;
}

五、函数指针数组

把函数的地址存到一个数组中,这个数组就叫函数指针数组。

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
int main()
{
	int(*pfarr[4])(int, int) = { Add,Sub,Mul,Div };//pfarr是函数指针数组
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		int r = pfarr[i](8, 4);
		printf("%d\n", r);
	}
	return 0;
}

函数指针数组:int  (*pfarr[4])(int,int) ——上面代码

函数指针数组类型:int  (*)( ) 

六、转移表

 函数指针的用途:转移表

计算器的一般实现:

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
int main()
{
	int x = 0;
	int y = 0;
	int z = 0;
	int input = 1;
	do
	{
		printf("*********************\n");
		printf("**** 1.Add 2.Sub ****\n");
		printf("**** 3.Mul 4.Div ****\n");
		printf("**** 0.exit      ****\n");
		printf("*********************\n");
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入两个数:");
			scanf("%d %d", &x, &y);
			z = Add(x, y);
			printf("%d\n", z);
			break;
		case 2:
			printf("请输入两个数:");
			scanf("%d %d", &x, &y);
			z = Sub(x, y);
			printf("%d\n", z);
			break;
		case 3:
			printf("请输入两个数:");
			scanf("%d %d", &x, &y);
			z = Mul(x, y);
			printf("%d\n", z);
			break;
		case 4:
			printf("请输入两个数:");
			scanf("%d %d", &x, &y);
			z = Div(x, y);
			printf("%d\n", z);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("输入错误\n");
			break;
		}
	} while (input);
	return 0;
}

使用函数指针数组实现:

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
int main()
{
	int x = 0;
	int y = 0;
	int z = 0;
	int input = 1;
	int(*pfarr[5])(int, int) = { 0,Add,Sub,Mul,Div };
	do
	{
		printf("*********************\n");
		printf("**** 1.Add 2.Sub ****\n");
		printf("**** 3.Mul 4.Div ****\n");
		printf("**** 0.exit      ****\n");
		printf("*********************\n");
		printf("请选择:");
		scanf("%d", &input);

		if (input >= 1 && input <= 4)
		{
			printf("请输入两个数:");
			scanf("%d %d", &x, &y);
			z = pfarr[input](x, y);
			printf("%d\n", z);
		}
		else if (input == 0)
		{
			printf("退出\n");
		}
		else
		{
			printf("输入错误\n");
		}
	} while (input);
	return 0;
}

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

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

相关文章

Android 10.0 Launcher3拖拽图标进入hotseat自适应布局功能实现一

1.前言 在10.0的系统rom定制化开发中&#xff0c;在对于launcher3的一些开发定制中&#xff0c;在对hotseat的一些开发中&#xff0c;需要实现动态hotseat居中 的功能&#xff0c;就是在拖拽图标进入和拖出hotseat&#xff0c;都可以保持hotseat居中的功能&#xff0c;接下来分…

html2canvas + jspdf 纯前端HTML导出PDF的实现与问题

前言 这几天接到一个需求&#xff0c;富文本编辑器的内容不仅要展示出来&#xff0c;还要实现展示的内容导出pdf文件。一开始导出pdf的功能是由后端来做的&#xff0c;然后发现对于宽度太大的图片&#xff0c;导出的pdf文件里部分图片内容被遮盖了&#xff0c;但在前端是正常显…

S参数入门

一、说明 S参数全称为散射参数&#xff0c;主要用来作为描述线性无源互联结构的一种行为模型&#xff0c;来源于网络分析方法。网络分析法是一种频域方法&#xff0c;在一组离散的频率点上&#xff0c;通过在输入和输出端口得到的参量完全描述线性时不变系统&#xff08;定义参…

园区AR导航系统构建详解:从三维地图构建到AR融合导航的实现

随着现代园区规模的不断扩大与功能的日益复杂&#xff0c;传统的二维地图导航已难以满足访客高效、精准定位的需求。园区内部错综复杂的布局、频繁变更的商户位置常常让访客感到迷茫&#xff0c;造成寻路上的时间浪费。园区AR导航系统以创新的技术手段&#xff0c;破解了私域地…

对redis进行深入学习

目录 1. 什么是redis&#xff1f;1.1 为什么使用redis作为缓存&#xff1f;1.1.0 数据库&#xff08;MySQL&#xff09;与 redis1. 存储介质不同&#xff08;408选手应该都懂hh&#xff09;2. 数据结构优化3. I/O模型差异4. CPU缓存友好性5. 单线程与多线程差异6. 持久化与缓存…

Volatility:分析MS10-061攻击

1、概述 # 1&#xff09;什么是 Volatility Volatility是开源的Windows&#xff0c;Linux&#xff0c;MaC&#xff0c;Android的内存取证分析工具。基于Python开发而成&#xff0c;可以分析内存中的各种数据。Volatility支持对32位或64位Wnidows、Linux、Mac、Android操作系统…

2024算力基础设施安全架构设计与思考(免费下载)

算网安全体系是将数据中心集群、算力枢纽、一体化大数据中心三个层级的安全需求进行工程化解耦&#xff0c;从国家安全角度统筹设计&#xff0c;通过安全 服务化方式&#xff0c;依托威胁情报和指挥协同通道将三层四级安全体系串联贯通&#xff0c;达成一体化大数据安全目标。 …

插画插件:成都亚恒丰创教育科技有限公司

【插画插件&#xff1a;数字创意时代的艺术加速器】 在数字化浪潮汹涌的今天&#xff0c;视觉艺术以其独特的魅力穿梭于互联网的每一个角落&#xff0c;成为连接人心、传递情感与信息的桥梁。而在这股创意洪流中&#xff0c;插画插件以其高效、便捷、个性化的特点&#xff0c;…

1219:马走日

#include<bits/stdc.h> using namespace std; int vis[8][2]{-2,1,-1,2,1,2,2,1,2,-1,1,-2,-1,-2,-2,-1};//构造偏移量数组 int t,n,m,x,y,ans;//棋盘总共由(n)(m)个点 bool st[100][100];//如果st[i][j]0 表示i,j这个坐标没有走过 st[a][b]1表示a,b这个坐标走过 void d…

【05】LLaMA-Factory微调大模型——初尝微调模型

上文【04】LLaMA-Factory微调大模型——数据准备介绍了如何准备指令监督微调数据&#xff0c;为后续的微调模型提供高质量、格式规范的数据支撑。本文将正式进入模型微调阶段&#xff0c;构建法律垂直应用大模型。 一、硬件依赖 LLaMA-Factory框架对硬件和软件的依赖可见以下…

GPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建

原文链接&#xff1a;GPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247608565&idx3&snd4e9d447efd82e8dd8192f7573886dab&chksmfa826912cdf5e00414e01626b52bab83a96199a6bf69cbbef7f7fe…

C语言 | Leetcode C语言题解之第257题二叉树的所有路径

题目&#xff1a; 题解&#xff1a; char** binaryTreePaths(struct TreeNode* root, int* returnSize) {char** paths (char**)malloc(sizeof(char*) * 1001);*returnSize 0;if (root NULL) {return paths;}struct TreeNode** node_queue (struct TreeNode**)malloc(size…

Mysql中的几种常见日志

引言 本文是对Mysql中几种常见日志及其作用的介绍 一、error log&#xff08;错误日志&#xff09; MySQL 中的 error log&#xff08;错误日志&#xff09;是一种非常重要的日志类型&#xff0c;它记录了 MySQL 服务器在启动、运行及关闭过程中遇到的所有重要事件、错误信…

python爬虫实现简单的代理ip池

python爬虫实现简单的代理ip池 我们在普通的爬虫过程中经常遇到一些网站对ip进行封锁的 下面演示一下普通的爬虫程序 使用requests.get爬取数据 这段代码是爬取豆瓣排行榜的数据&#xff0c;使用f12来查看请求的url和数据格式 代码 def requestData():# 爬取数据的urlur…

[Maven] 打包编译本地Jar包报错的几种解决办法

目录 方式1&#xff1a;通过scope指定 方式2&#xff1a;通过新建lib 方式3&#xff1a;通过build节点打包依赖​​​​​​​ 方式4&#xff1a;安装Jar包到本地 方式5&#xff1a;发布到远程私有仓库 方式6&#xff1a;删除_remote.repositories 方式7&#xff1a;打包…

Leetcode二分搜索法浅析

文章目录 1.二分搜索法1.1什么是二分搜索法&#xff1f;1.2解法思路 1.二分搜索法 题目原文&#xff1a; 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返…

TCP重传机制详解

1.什么是TCP重传机制 在 TCP 中&#xff0c;当发送端的数据到达接收主机时&#xff0c;接收端主机会返回⼀个确认应答消息&#xff0c;表示已收到消息。 但是如果传输的过程中&#xff0c;数据包丢失了&#xff0c;就会使⽤重传机制来解决。TCP的重传机制是为了保证数据传输的…

决策树回归(Decision Tree Regression)

理论知识推导 决策树回归是一种非参数监督学习方法&#xff0c;用于回归问题。它通过将数据集划分成较小的子集来建立模型&#xff0c;并在这些子集上构建简单的预测模型&#xff08;通常是恒定值&#xff09;。下面是决策树回归的数学推导过程&#xff1a; 实施步骤与参数解读…

紫光展锐5G安卓核心板T760__国产手机芯片方案

展锐T760安卓核心板是具备续航和性能更加均衡的5G移动平台。其主要特点包括主流的6400万像素摄像头和高达120Hz的刷新率。 平台采用多模融合的创新架构和AI智能调节技术&#xff0c;从而在5G数据场景下降低了37%的整体功耗&#xff0c;在5G待机场景下降低了18%的整体功耗。 多…

遇到报错:无法安装 “WebDriverAgentRunner-Runer“ 无法安装此app,因为无法验证其完整性,如何解决

嗨&#xff0c;大家好&#xff0c;我是兰若&#xff0c;相信很多人在做app自动化测试时&#xff0c;都遇到过这种报错&#xff1a;无法安装 “WebDriverAgentRunner-Runer” 无法安装此app,因为无法验证其完整性。 以下是一些解决思路&#xff1a; 这个问题通常是由于 iOS 设…