c语言-浅谈指针(3)

news2024/11/24 16:02:03

文章目录

    • 1.字符指针变量
      • 常见的字符指针初始化
      • 另一种字符指针初始化
      • 例:
    • 2.数组指针变量
      • 什么是数组指针变量
      • 数组指针变量创建
      • 数组指针变量初始化
      • 例(二维数组传参的本质)
    • 3.函数指针变量
      • 什么是函数指针变量呢?
      • 函数指针变量创建
      • 函数指针使用
      • typedef关键字
    • 4.函数指针数组
      • 概念
      • 创建
      • 通过函数指针数组实现计算器


1.字符指针变量

常见的字符指针初始化

字符指针 char *

常见的初始化:

int main() {
	char a = 'w';
	char* p = &a;
	return 0;
}

跟 int *类型的初始化一样,下面介绍另一种字符指针的初始化

另一种字符指针初始化

这种是将一个字符串直接赋给字符指针变量

如:

char* p = "abcdefg";

那么它能不能像一般的字符数组那样直接打印出来呢,我们通过代码看看:

int main() {
	char a[] = "abcdefg";
	char* p = "abcdefg";
	printf("%s", a);//打印字符数组
	printf("%s", *p);//打印指针初始化出来的字符串
	return 0;
}

运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/35a2012446a34c129a0a10bb3d6b4703.png

由结果看出:只有字符数组打印出来了,而字符指针没打印出来,这是为什么呢? 其实是因为这样初始化只是把字符串的首个字符的地址传给字符指针变量 p ,这样的话 *p=a。 在这里%s是打印字符串的,所以打印不了一个字符。

那我们用打印一个字符的 %c 试试

int main() {
	char a[] = "abcdefg";
	char* p = "abcdefg";
	printf("%s\n", a);
	printf("%c", *p);
	return 0;
}

运行结果
在这里插入图片描述
字符指针只打印一个首字符,验证了首个字符的地址传给字符指针变量 p

那么我们可以用循环的方式将这个字符串打印出来

int main() {
	char* p = "abcdefg";
	int s = strlen(p);//求字符长度
for(int i=0;i<s;i++)
	printf("%c", *(p+i));//将字符一一打印出来
	return 0;
}

运行结果
在这里插入图片描述

例:

这是《剑指offer》中⼀道和字符串相关的笔试题,问最后输出的结果是什么?
代码:

#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;}

答案:
在这里插入图片描述

分析:
1.这道题其实就是比较首地址 2这⾥str3和str4指向的是⼀个同⼀个常量字符串。C/C++会把常量字符串存储到单独的⼀个内存区域,当⼏个指针指向同⼀个字符串的时候,他们实际会指向同⼀块内存。但是⽤相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。

2.数组指针变量

数组指针是指针不是数组

什么是数组指针变量

我们通过其他类型的指针进行类比一下 整形指针变量: int * pint; 存放的是整形变量的地址,能够指向整形数据的指针。 浮点型指针变量: float * pf; 存放浮点型变量的地址,能够指向浮点型数据的指针。 那么数组指针变量就是存放数组地址,指向数组的指针变量吧

数组指针变量创建

创建:int (*p)[10]
解释:p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。所以p是⼀个指针,指向⼀个数组,叫数组指针。
注意:[ ]的优先级要于 * 号的,所以必须加上()来保证p先和 * 结合。

数组指针变量初始化

数组指针是用来存放数组的指针的,那么我们将数组取地址在赋给数组指针变量即可
如:

int arr[10] = { 1,2,3,4,5,7,8,9,0.6 };
int(*p)[10] = &arr;

解释:
在这里插入图片描述
图解(一维数组)
在这里插入图片描述

例(二维数组传参的本质)

在数组里面的二维数组可以看成一个一维数组,只不过是每个元素就是一个数组而已,所以,根据数组名是数组元素的地址这个规则,⼆维数组的数组名表⽰的就是第⼀⾏的地址,是⼀维数组的地址。

在这里插入图片描述
1.通过二维数组接收参数
这是一般的方法

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

	return 0;
}

2.通过数组指针来了解二维数组的本质

void qin(int(*p)[5]) {//*(p+1)==arr[0]+j
	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 5; j++)
			printf("%d ", (*(p + i))[j]);//  
			//(*p)==*(p+i),当i 加1时相当于跳过二维数组中的一个一维数组,
			//当然跟据前面的知识也可以写成这样 *(*(p+i)+j)
}
	printf("\n");
}
int main() {
	int arr[2][5] = { 1,2,3,4,5,6,7,8,9,0 };
	qin(arr);//在前面指针内容里说过,数组名就是首元素的地址,
	//那么我们这里把二维数组当成一维数组,那么首元素不就是一整个一维数组的地址吗

	return 0;
}

图解:
在这里插入图片描述
总结:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。

3.函数指针变量

什么是函数指针变量呢?

数组指针是用来存数组的地址的那么函数指针呢?
其实函数指针也是用来存地址的,存的是函数的地址,这里就有很多人有疑问了,函数有地址?
那么我们来做个测试:

int add(int x, int y) {
	return x + y;
}
int main() {
	printf("%p", &add);
	return 0;
}

运行结果:
在这里插入图片描述
很明显函数是有地址

这里还有一个注意的是函数名和&函数名都是代表函数的地址,如:add==&add

我们来测试一下吧

int add(int x, int y) {
	return x + y;
}
int main() {
	printf("&add=%p\n", &add);
	printf("add=%p", add);
	return 0;
}

运行结果:
在这里插入图片描述
耶,是一样的

函数指针变量创建

创建:int (*p) (int, int)
在这里插入图片描述

函数指针使用

我们用函数指针来实现一下加法

int add(int x, int y) {
	return x + y;
}
int main() {
	int (*p)(int, int) = add;
	int a = 3, b = 9;
	printf("%d\n", p(a, b));//这里不用 * 也可以因为函数调用的时候本身就是用地址去调用
	printf("%d\n", (*p)(a, b));
	return 0;
}

运行结果:
在这里插入图片描述

typedef关键字

typedef 是⽤来类型重命名的,可以将复杂的类型,简单化。

如:

typedef unsigned int uint;
//将unsigned int 重命名为uint

那么如何来重命名指针类型呢

typedef  int(*)(int ,int)   te  //错误
typedef  int(*te)(int, int)   //正确命名,将重命名放到原来放函数指针名称的位置
typedef  (*te)[10]//数组指针重命名

4.函数指针数组

概念

把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组(就是将函数指针放到一个数字里)

创建

int (*) (intint)//函数指针类型
int  (*p[10])(int ,int)//函数指针数组--p先和[]结合形成数组,再和函数指针类型结合形成函数指针数组

通过函数指针数组实现计算器

我们这里要实现一个简单的计算器,分别有加法、减法、乘法、除法,那么我们就要实现四个函数来实现,然后还要一个选择来选择实行什么计算,最后还需要一个菜单就完成了

我们先用一般的方法来实现计算器:

#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;
 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);
 ret = add(x, y);
 printf("ret = %d\n", ret);
 break;
 case 2:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = sub(x, y);
 printf("ret = %d\n", ret);
 break;
 case 3:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = mul(x, y);
 printf("ret = %d\n", ret);
 break;
 case 4:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = div(x, y);
 printf("ret = %d\n", ret);
 break;
 case 0:
 printf("退出程序\n");
 break;
 default:
 printf("选择错误\n");
 break;
 }
 } while (input);
 return 0;
}

使⽤函数指针数组的实现:

我们将这4个函数都放到一个函数指针数组里,当我们需要实行什么计算就通过什么下标来访问这个函数

#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 }; 
 //储存函数地址,这里的0也算一个地址,我们这样是方便选择
 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 <= 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" ); 
 }

以上就是我的分享
谢谢大家的观看!

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

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

相关文章

C语言基本算法----冒泡排序

原理 冒泡排序就是对一个存放N个数据的数组进行N次扫描&#xff0c;每次把最小或者最大的那个元素放到数组的最后&#xff0c;达到排序的目的。 原理图解 冒泡排序过程分析 冒泡排序的执行过程 冒泡排序总结 在此感谢 冒泡排序法_哔哩哔哩_bilibili 这篇blog是对这位up此视…

二维码智慧门牌管理系统升级解决方案:门牌聚合,让管理更便捷!

文章目录 前言一、传统门牌管理系统的瓶颈二、地图门牌聚合展示的优势三、地图门牌聚合展示的实现方法四、智慧门牌管理系统的未来发展 前言 随着城市的发展和建设&#xff0c;对于地址信息的管理变得越来越重要。而智慧门牌管理系统作为管理地址信息的重要工具&#xff0c;其…

Linux--网络概念

1.什么是网络 1.1 如何看待计算机 我们知道&#xff0c;对于计算机来说&#xff0c;计算机是遵循冯诺依曼体系结构的&#xff08;即把数据从外设移动到内存&#xff0c;再从内存到CPU进行计算&#xff0c;然后返回内存&#xff0c;重新读写到外设中&#xff09;。这是一台计算机…

机器人走迷宫问题

题目 1.房间有XY的方格组成&#xff0c;例如下图为64的大小。每一个方格以坐标(x,y) 描述。 2.机器人固定从方格(0, 0)出发&#xff0c;只能向东或者向北前进&#xff0c;出口固定为房间的最东北角&#xff0c;如下图的 方格(5,3)。用例保证机器人可以从入口走到出口。 3.房间…

英伟达AI布局的新动向:H200 GPU开启生成式AI的新纪元

英伟达Nvidia是全球领先的AI计算平台和GPU制造商&#xff0c;近年来一直在不断推出创新的AI产品和解决方案&#xff0c;为各行各业的AI应用提供强大的支持。 最近&#xff0c;英伟达在GTC 2023大会上发布了一款专为训练和部署生成式AI模型的图形处理单元&#xff08;GPU&#…

如何实现用户未登录不可访问系统

在开发web系统时&#xff0c;如果用户不登录&#xff0c;发现用户也可以直接正常访问系统&#xff0c;这种设计本身并不合理&#xff0c;那么我们希望看到的效果是&#xff0c;只有用户登录成功之后才可以正常访问系统&#xff0c;如果没有登录则拒绝访问。那么我们可以使用过滤…

回溯算法(3)--n皇后问题及回溯法相关习题

一、n皇后问题 1、概述 n皇后要求在一个nn的棋盘上放置n个皇后&#xff0c;使得他们彼此不受攻击&#xff0c;皇后可以攻击同一行、同一列、同一斜线上的敌人&#xff0c;所以n皇后问题要求寻找在棋盘上放置这n个皇后的方案&#xff0c;使得任意两个皇后都不在同一行、同一列或…

口袋参谋:一键下载任意买家秀图片、视频,是怎么做到的!

​对于淘宝商家来说&#xff0c;淘宝买家秀是非常的重要的。买家秀特别好看的话&#xff0c;对于提升商品的销量来说&#xff0c;会有一定的帮助&#xff0c;如何下载别人的买家秀图片&#xff0c;然后用到自己的店铺中呢&#xff1f; 这里我可以教叫你们一个办法&#xff01;那…

ROS基础—关于参数服务器的操作

1、rosparam list 获取参数服务器的所有参数。 2、rosparam get /run_id 获取参数的值

【uniapp】使用扫码插件,解决uni.scanCode扫码效率低的问题

1. 背景 uniapp 中自带的二维码扫描的 API 是 uni.scanCode&#xff0c;但有如下问题&#xff1a; 二维码扫描的效率不高&#xff0c;有些需要扫2秒左右 较小或模糊的一些二维码无法识别出来&#xff0c;多次扫同样的一个码可能出现扫码失败的情况 受环境影响大&#xff0c…

腾讯云服务器怎么买便宜?腾讯云服务器新人专享限时特惠购买链接

腾讯云作为国内领先的云计算服务提供商之一&#xff0c;为个人用户和企业用户提供了多种优惠活动。这些活动不仅能帮助用户节省成本&#xff0c;还能提升企业的效益。本文将介绍腾讯云的多重优惠活动&#xff0c;让用户能够以更优惠的价格购买和续费云服务器。 腾讯云双十一领…

动手学深度学习——循环神经网络的简洁实现(代码详解)

文章目录 循环神经网络的简洁实现1. 定义模型2. 训练与预测 循环神经网络的简洁实现 # 使用深度学习框架的高级API提供的函数更有效地实现相同的语言模型 import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2lbatch_size, …

解决docker运行elastic服务端启动不成功

现象&#xff1a; 然后查看docker日志&#xff0c;发现有vm.max_map_count报错 ERROR: [1] bootstrap checks failed [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144] 解决办法&#xff1a; 1. 宿主机&#xff08;运行doc…

【springboot笔记】程序可用性检测ApplicationAvailability

1.背景 springboot-3.1.5 ApplicationAvailability LivenessState ReadinessState AvailabilityChangeEvent 我们可以通过ApplicationAvailability获取当前应用程序的可用性&#xff0c;这个可用性包括ApplicationContext和对外请求路由两种。 LivenessState 是表示Applicatio…

【C++】类与对象 II 【深入浅出 万字详解】

类与对象 II 一、类的6个默认成员函数二、构造函数前言&#xff1a;构造函数产生的由来 及引入C语言中关于初始化会出现的问题总结&#xff1a;&#xff08;一&#xff09;构造函数的 概念&#xff08;二&#xff09;构造函数的 特性★ 构造函数 和 函数声明 的区分 三、析构函…

数学建模 | 灰色预测原理及python实现

目录 一、灰色预测的原理 二、灰色预测的应用及python实现 一、灰色预测的原理 灰色预测是以灰色模型为基础&#xff0c;灰色模型GM(n,h)是微分方程模型&#xff0c;可用于描述对象做长期、连续、动态的反应。其中&#xff0c;n代表微分方程式的阶数&#xff0c;h代表微分方…

下一代搜索引擎会什么?

现在是北京时间2023年11月18日。聊一聊搜索。 说到搜索&#xff0c;大家首先想到的肯定是谷歌&#xff0c;百度。我把这些定义成上一个时代的搜索引擎。ChatGPT已经火热了有一年的时间了&#xff0c;大家都认为Ai搜索是下一代的搜索。但是AI搜索&#xff0c;需要的是很大算力&a…

【动态规划】求解编辑距离问题

目录 问题描述递推关系运行实例时空复杂度优化Hirschberg 算法 问题描述 编辑距离问题是求解将⼀个字符串转换为另⼀个字符串所需的插⼊、删除、替换的最小次数。 C O M M O M → s u b C O M M U M → s u b C O M M U N → i n s C O M M U N E \mathbb{COMMOM} \overset{sub…

迪杰斯特拉算法(C++)

目录 介绍&#xff1a; 代码&#xff1a; 结果&#xff1a; 介绍&#xff1a; 迪杰斯特拉算法&#xff08;Dijkstras algorithm&#xff09;是一种用于计算加权图的单点最短路径的算法。它是由荷兰计算机科学家Edsger W. Dijkstra在1956年发明的。 该算法的思路是&#xf…

Confluence 快速安装教程

安装jdk yum install -y java-1.8.0-openjdk.x86_64 java -version 安装MySQL mkdir -p /data/mysql/data chmod 777 /data/mysql/datadocker rm -f mysql docker run -d --name mysql \-p 3306:3306 \-e MYSQL_ROOT_PASSWORDfingard1 \-v /data/mysql/data:/var/lib/mysql …