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

一、字符指针变量

在指针的类型中,有字符指针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");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("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.rhkb.cn/news/376906.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Vulnhub] Sedna BuilderEngine-CMS+Kernel权限提升

信息收集 IP AddressOpening Ports192.168.8.104TCP:22, 53, 80, 110, 111, 139, 143, 445, 993, 995, 8080, 55679 $ nmap -p- 192.168.8.104 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 6.6.1p1 Ubuntu 2ubuntu2 …

强化学习编程实战-5 基于时间差分的方法

第4章中&#xff0c;当模型未知时&#xff0c;由于状态转移概率P未知&#xff0c;动态规划中值函数的评估方法不再适用&#xff0c;用蒙特卡洛的方法聘雇值函数。 在蒙特卡洛方法评估值函数时&#xff0c;需要采样一整条轨迹&#xff0c;即需要从初始状态s0到终止状态的整个序列…

“论软件维护方法及其应用”写作框架,软考高级论文,系统架构设计师论文

论文真题 软件维护是指在软件交付使用后&#xff0c;直至软件被淘汰的整个时间范围内&#xff0c;为了改正错误或满足 新的需求而修改软件的活动。在软件系统运行过程中&#xff0c;软件需要维护的原因是多种多样的&#xff0c; 根据维护的原因不同&#xff0c;可以将软件维护…

DockerSecret+DockerConfig介绍及使用

DockerSecret 查看官网介绍&#xff0c;Secret是daemon API 1.25之后引入的&#xff0c;它运行在swarm上的命令。 生产环境下&#xff0c;为了安全&#xff0c;我们不能把各项目的配置密码写入到配置文件。 我们可以引入docker的secret方式保护密码。 场景&#xff1a; 用…

数据结构之链表操作详解与示例(反转链表,合并链表,旋转链表,对链表排序)

文章目录 1. 反转链表2. 合并链表3. 旋转链表4. 对链表排序总结 链表是一种常见的基础数据结构&#xff0c;它在内存中的存储方式非常灵活。本文将详细介绍反转链表、合并链表、旋转链表以及对链表排序这四种操作&#xff0c;并提供C和C的实现示例。 1. 反转链表 反转链表意味…

【数学建模】——【线性规划】及其在资源优化中的应用

目录 线性规划问题的两类主要应用&#xff1a; 线性规划的数学模型的三要素&#xff1a; 线性规划的一般步骤&#xff1a; 例1&#xff1a; 人数选择 例2 &#xff1a;任务分配问题 例3: 饮食问题 线性规划模型 线性规划的模型一般可表示为 线性规划的模型标准型&…

AI大模型探索之旅:深潜大语言模型的训练秘境

在人工智能的浩瀚星空中&#xff0c;大语言模型无疑是最耀眼的星辰之一&#xff0c;它们以无与伦比的语言理解与生成能力&#xff0c;引领着智能交互的新纪元。本文将带您踏上一场探索之旅&#xff0c;深入大语言模型的训练秘境&#xff0c;揭开其背后复杂而精妙的全景画卷。 …

免杀笔记 ----> 动态调用

前一段时间不是说要进行IAT表的隐藏吗&#xff0c;终于给我逮到时间来写了&#xff0c;今天就来先将最简单的一种方式 ----> 动态调用&#xff01;&#xff01;&#xff01; 1.静态查杀 这里还是说一下我们为什么要对他进行隐藏呢&#xff1f;&#xff1f;&#xff1…

CAN总线学习

can主要用于汽车、航空等控制行业&#xff0c;是一种串行异步通信方式&#xff0c;因为其相较于其他通信方式抗干扰能力更强&#xff0c;更加稳定。原因在于CAN不像其他通信方式那样&#xff0c;以高电平代表1&#xff0c;以低电平代表0&#xff0c;而是通过电压差来表示逻辑10…

STM32MP135裸机编程:唯一ID(UID)、设备标识号、设备版本

0 资料准备 1.STM32MP13xx参考手册1 唯一ID&#xff08;UID&#xff09;、设备标识号、设备版本 1.1 寄存器说明 &#xff08;1&#xff09;唯一ID 唯一ID可以用于生成USB序列号或者为其它应用所使用&#xff08;例如程序加密&#xff09;。 &#xff08;2&#xff09;设备…

使用Python和MediaPipe实现手势虚拟鼠标控制

概述 使用Python实现虚拟鼠标控制&#xff0c;利用手势识别来替代传统鼠标操作。这一实现依赖于计算机视觉库OpenCV、手势识别库MediaPipe以及其他辅助库如PyAutoGUI和Pynput。 环境配置 在开始之前&#xff0c;请确保已安装以下Python库&#xff1a; pip install opencv-p…

SadTalker数字人服务器部署

一、单独SadTalker部署 git clone https://github.com/OpenTalker/SadTalker.gitcd SadTalker conda create -n sadtalker python3.8conda activate sadtalkerpip install torch1.12.1cu113 torchvision0.13.1cu113 torchaudio0.12.1 --extra-index-url https://download.pyto…

RuoYi-后端管理项目入门篇1

目录 前提准备 下载若依前后端 Gitee 地址 准备环境 后端数据库导入 1 克隆完成 若依后端管理后端 Gitte 地址 :若依/RuoYi-Vue 2.1 创建Data Source数据源 2.2 填写好对应的数据库User 和 Password 点击Apply 2.3 新建一个Schema 2.4 填写对应数据库名称 这边演示写的…

husky 和 lint-staged 构建代码项目规范

目录 前言 最简单的方法 过 scripts 来解决如果检测工具多&#xff0c;需要多次处理 通过 husky(哈士奇)来解决容易遗忘的问题 1. 安装 2. husky init 3. 试一试​ lint-stadge 只 lint 改动的 1. 安装 2. 修改 package.json 配置 3. 添加 npm 脚本: 4.使用 Husky…

缓存与分布式锁

一、缓存 1、缓存使用 为了系统性能的提升&#xff0c;我们一般都会将部分数据放入缓存中&#xff0c;加速访问。 适合放入缓存的数据有&#xff1a; 即时性、数据一致性要求不高的&#xff1b;访问量大且更新频率不高的数据。 在开发中&#xff0c;凡是放入缓存中的数据我们都…

语言主要是一种交流工具,而不是思维工具?GPT5何去何从?

引言 在人工智能领域&#xff0c;特别是大语言模型&#xff08;LLM&#xff09;的发展中&#xff0c;语言和思维的关系一直是一个备受关注的话题。近期&#xff0c;麻省理工学院&#xff08;MIT&#xff09;在《Nature》杂志上发表了一篇题为《Language is primarily a tool f…

【ChatGPT】深入解析Prompt提示词及如何高效使用ChatGPT

一、Prompt提示词是什么&#xff1f; 1.1 Prompt的定义 Prompt是人工智能领域中的一个关键概念&#xff0c;尤其在自然语言处理&#xff08;NLP&#xff09;和生成型AI模型中。简而言之&#xff0c;prompt是一段文本或指令&#xff0c;用于引导或启动AI模型的特定响应或操作。…

Linux - 基础开发工具(yum、vim、gcc、g++、make/Makefile、git)

目录 Linux软件包管理器 - yum Linux下安装软件的方式 认识yum 查找软件包 安装软件 如何实现本地机器和云服务器之间的文件互传 卸载软件 Linux编辑器 - vim vim的基本概念 vim下各模式的切换 vim命令模式各命令汇总 vim底行模式各命令汇总 vim的简单配置 Linux编译器 - gc…

Spring-Cache 缓存

1.简介 2.SpringCache 整合 简化缓存开发 1.导入依赖 <!-- spring cache --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>2.redis 作为缓存…

Mac应用程序清理卸载工具:App Cleaner Uninstaller for Mac 中文版

App Cleaner Pro是一款Mac上非常好用的软件卸载工具&#xff0c;支持应用卸载、Widget卸载、浏览器插件卸载&#xff0c;支持拖拽卸载和列表卸载&#xff0c;能够非常干净的卸载应用&#xff0c;节省你的磁盘空间。App Cleaner Uninstaller Pro是一款深度清理和卸载的工具&…