【c语言】深入理解指针(2)

1. 字符指针变量

可以利用字符指针存放字符数组来间接存放字符串。

int main()
{char arr[10] = "abcdef";char* p = arr;printf("p  = %s\n", p);return 0;
}

那我们可不可以直接给字符指针存放字符串呢? 

int main()
{char* p1 = "abcdef";printf("p1 = %s\n", p1);return 0;
}

我们来看一下结果:

可以看到是可以直接给字符指针存放字符串,其实指针仅仅存放了字符串首字母的地址,%s会根据这个首字母的地址依次打印字符,当遇到空字符‘\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");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;
}

先来看str1和str2,在一篇文章中已经讲过数组名是数组首元素的地址,所以str1和str2分别是数组str1[]和数组的str2[]的首地址,而两个不同的数组是不会存放在同一个位置的,所以str1和str2是不相等的。

再来看str3和str4,str3和str4都是存放常量字符串的首地址,而当字符指针直接指向一个字符串字面量时,该字面量通常存储在程序的只读数据段,在只读数据段中是不会开辟两个空间存放相同的字面量的,也就是说*str3和*str4指向的"hello bit."是同一个字符串,所以str3和str4存放的地址是相同的。

2. 数组指针变量

2.2 数组指针变量是什么

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

指针数组与数组指针:

指针数组:

int* p1[10];

[]的优先级是比*的优先级高的,所以p1先和[]结合。p1[10]是一个数组,这个数组存放的是int*类型的元素,也就是存放着指针类型的元素,所以p1是一个指针数组。

数组指针:

int (*p2)[10];

()的优先级是比[]高的,所以*与p2结合,p2是指针变量,后面的[10]表示,p2指向一个存放着10元素的数组,int表示数组的每个元素的类型是int类型。

总的来说,指针数组是数组,数组指针数指针

 2.3 数组指针变量怎么初始化

数组名只是表示首元素的地址,而取地址数组名才是表示整个元素的地址,所以在给数组指针初始化的时候我们应该取地址数组名,才会存下整个数组的地址。

int arr[10] = { 0 };
int(*p2)[10] = &arr;

3. 二维数组的传参本质

数组名是数组首元素的地址,那二维数组中谁是首元素?

二维数组的首元素就是第一行,首元素的地址就是第一行的地址,第一行的地址是一个一维数组的地址,所以二维数组在传参的时候,如果需要用指针去接收,就要用一维数组指针。

void print(int(*p)[5], int a, int b)
{for (int i = 0; i < a; i++){for (int j = 0; j < b; 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;
}

4. 函数指针变量

函数指针是指向函数的指针。

函数名代表的是函数的入口地址。我们只需要用函数指针存放这个入口地址就可以通过函数指针调用这个函数了,还有就是函数名与取地址函数名都是函数的入口地址,二者没有区别。

函数指针存放函数地址:

void Add(int x,int y)
{return x + y;
}
int main()
{int(*p)(int, int) = Add;return 0;
}

 通过函数指针调用函数:

一般通过调用函数名就可以调用函数了,而函数指针存放着函数的地址,所以我们可以不解引用直接通过函数指针调用函数,当然了也是可以通过解引用函数指针来调用函数的。

5. 函数指针数组

存放函数指针的数组是函数指针数组。 

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 (*p)(int, int) = Add;//p是函数指针变量int (*p1[])(int, int) = { Add,Sub,Mul,Div };//p1是函数指针数组return 0;
}

函数指针数组的调用: 

6. 转移表

转移表在C语言中通常指的是函数指针数组

转移表(也称为跳转表或分支表)是编程中用于实现多路分支选择的一种数据结构。它通常用于优化程序的执行效率,尤其是在需要根据不同的输入值进行不同操作的场景中。

在C语言中,转移表可以定义为一个包含函数指针的数组。每个数组元素都指向一个函数,这些函数代表了不同的操作或处理逻辑。通过索引访问这个数组,程序可以“跳转”到相应的函数并执行。这种方式比使用多个if-else语句或者switch-case语句更加高效,因为它可以直接通过数组索引来定位和调用函数,而不需要逐个判断条件。

举例:计算器的一般实现:

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;
}
void menu()
{printf("***************************\n");printf("******1.加法    2.减法*****\n");printf("******3.乘法    4.除法*****\n");printf("***********0.退出**********\n");printf("***************************\n");}
int main()
{int(*p[5])(int, int) = {0,Add,Sub,Mul,Div};int input;int x, y;do{menu();printf("请选择:");scanf("%d", &input);if (input > 0 && input < 5){printf("请输入两个操作数:");scanf("%d %d", &x, &y);printf("%d\n", p[input](x, y));}else if (input == 0){printf("退出计算器\n");}else{printf("请重新选择\n");}} while (input);return 0;
}

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

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

相关文章

【C#】.net core 6.0 创建默认Web应用,以及默认结构讲解,适合初学者

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

Octave实现位置式PID算法

由于Matlab不让用&#xff0c;只能“你不让爷用&#xff0c;爷就用别的”&#xff0c;选择开源的Octave以及scilab进行相关领域的学习。Octave的代码和Matlab几乎是100%相同的&#xff0c;只有一些专用的包的函数&#xff0c;可能有些还没来得及写&#xff0c;或者有些差异。但…

计算机网络概念、组成、功能和分类

文章目录 概要1.怎么学习计算机网络2.概念3.功能、组成4.工作方式、功能组成5.分类 概要 概念、组成、功能和分类 1.怎么学习计算机网络 2.概念 通信设备&#xff1a;比如路由器、路由器 线路&#xff1a;将系统和通信设备两者联系的介质之类的 计算机网络是互连的、自治的的计…

如何用DT浏览器建立视频播放系统

在DT浏览器官方网站下载最新版软件&#xff0c;安装&#xff0c;在DT浏览器首页点视频直播&#xff0c;软件会自动检测手机相册里的视频并且显示出来&#xff0c;选择需要播放的视频在直播间里播放。如果要建立节目单&#xff0c;需要在服务器上把播放顺序&#xff0c;视频名称…

一起玩儿物联网人工智能小车(ESP32)——57. SPI总线协议初探(一)

摘要&#xff1a;介绍SPI总线的基本知识 前面已经学习过IIC总线协议&#xff0c;今天开始介绍另一个总线协议——SPI。SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外设接口&#xff09;是由Motorola提出的一种高速、全双工、同步的通信总线。并且在芯片的管脚…

Oracle 面试题 | 17.精选Oracle高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

(每日持续更新)jdk api之ObjectInputFilter.Status基础、应用、实战

博主18年的互联网软件开发经验&#xff0c;从一名程序员小白逐步成为了一名架构师&#xff0c;我想通过平台将经验分享给大家&#xff0c;因此博主每天会在各个大牛网站点赞量超高的博客等寻找该技术栈的资料结合自己的经验&#xff0c;晚上进行用心精简、整理、总结、定稿&…

市场复盘总结 20240207

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 一支股票 10%的时候可以操作&#xff0c; 90%的时间适合空仓等待 二进三&#xff1a; 进级率中 75% 最常用…

JavaScript中call、apply、bind方法的应用与区别

在JavaScript中&#xff0c;call、apply和bind是函数的三个重要方法&#xff0c;它们虽然功能不同&#xff0c;但都可以用来改变函数的执行上下文或者传递参数。本文将分别介绍call、apply和bind方法的应用和区别&#xff0c;并附带示例代码。 一、call方法 call方法的作用是…

移动光猫gs3101超级密码及改桥接模式教程

文章目录 超级管理员账号改桥接模式路由器连接光猫&#xff0c;PPPOE拨号即可&#xff01;附录&#xff1a;如果需要改桥接的话不知道拨号密码咋办打开光猫Telnet功能Telnet 登录 参考文章 移动光猫吉比特GS3101超级账号获取更改桥接 移动光猫gs3101超级密码及改桥接模式教程 …

分享一下 uniapp 打包安卓apk

首先需要安装 Java 环境&#xff0c;这里就不做解释了 第二步&#xff1a;打开 mac 终端 / cmd 命令行工具 使用keytool -genkey命令生成证书 keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore *testalias 是证书别名&am…

华大基因PMseq病原微生物高通量基因检测产品耐药数据库持续

23年肺炎支原体感染的患者数量持续上升&#xff0c;与此同时&#xff0c;由肺炎支原体感染引发的住院患者数量也在迅速增加。这就导致近期儿科和发热门诊都处于床位爆满状态。而在疑难危重的肺炎患者中&#xff0c;肺炎支原体的检出率也在不断提高。华大基因PM Online线上数据管…

ELAdmin 的 CRUD

数据表结构 弄个测试的数据表&#xff0c;不同类型的几个字段&#xff0c;表名位 mp_reply。 生成代码 ELAdmin 可以自动生成代码。 左侧目录系统工具–代码生成&#xff0c;点开以后可以看到上面创建的数据表mp_reply&#xff0c;点击配置。 进入的页面内容有两部分&#…

【Linux笔记】缓冲区的概念到标准库的模拟实现

一、缓冲区 “缓冲区”这个概念相信大家或多或少都听说过&#xff0c;大家其实在C语言阶段就已经接触到“缓冲区”这个东西&#xff0c;但是相信大家在C语言阶段并没有真正弄懂缓冲区到底是个什么东西&#xff0c;也相信大家在C语言阶段也因为缓冲区的问题写出过各种bug。 其…

Blender教程(基础)-顶点的移动、滑移-16

一、顶点的移动与缩放 ShiftA新建柱体、切换到编辑模式 点模式下&#xff0c;选择一个顶点、选择移动&#xff08;GZ&#xff09;&#xff0c;发现顶点严Z轴移动&#xff0c;如下图所示 GY 按数字键盘7切换视图&#xff0c;选择这个面的所有顶点 按S把面缩放大 Ctrl…

TCP相关知识点

TCP相关知识点 参考&#xff1a; 《计算机网络》 (建议收藏)TCP协议灵魂之问&#xff0c;巩固你的网路底层基础 关于 TCP 三次握手和四次挥手&#xff0c;满分回答在此 (值得看) TCP处于网络体系结构中的运输层。 运输层主要为应用进程提供端到端的逻辑通信&#xff0c;然后对…

双非本科准备秋招(19.1)—— Synchronized优化

轻量级锁 流程 一个对象虽然有多线程加锁&#xff0c;但是加锁时间是错开的&#xff0c;那么可以用轻量级锁优化。 语法还是synchronized&#xff0c;只是对使用者是透明的。 static final Object obj new Object(); public static void method1() {synchronized( obj ) {//…

代码随想录算法训练营第42天 | 01背包理论基础 416.分割等和子集

01背包理论基础 问题定义&#xff1a;有n件物品和一个能装重量为w的背包&#xff0c;第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i]。每件物品只能用一次&#xff0c;求解将哪些物品装入背包获得的总价值最大。dp数组含义&#xff1a;dp[i][j] 表示从下标为 [0…

(篇九)MySQL常用内置函数

目录 ⌛数学函数 ⌛字符串函数 ⌛聚合函数 ⌛日期函数 &#x1f4d0;获取当前时间 &#x1f4d0;获取时间的某些内容 &#x1f4d0;​编辑 &#x1f4d0;格式化函数 &#x1f4cf;format类型&#xff1a; ⌛系统信息函数 ⌛类型转换函数 数学函数 字符串函数 聚合函…

3060ti显卡+cuda12.1+win10编译安装生成fastdeploy的c++与python库

在cuda12中,调用官方发布的fastdeploy会出现报错,故此自行编译fastdeploy库。 官网编译教程:https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/gpu.md 可选编译选项 编译选项 无论是在何平台编译,编译时仅根据需求修改如下选项,勿…