关于在c++中使用数组名作为函数参数,或者使用数组名的地址作为函数参数问题的一些研究

前言

使用数组名作为函数参数,或者使用数组名的地址作为函数参数,常常出现于对于字符串的读入问题之中。

常有以下两种写法:

  1. 这是使用数组名作为函数参数
#include<cstdio>
char s[100];
int main() {scanf("%s",s);
}

在编译时不会出现报错和警告。

2.这是使用数组名的地址作为函数参数

#include<cstdio>
char s[100];
int main() {scanf("%s",&s);
}

在编译的时候不会报错,默认不会有警告。但是编译选项中开启-Wall(显示全部警告)就会出现警告。

在这里插入图片描述

警告的原因是,scanf函数的%s选项期望获得一个字符类型的地址,作为读入字符串的起始地址。而&s事实上是一个字符数组类型的地址,而不是字符类型地址。

-Wall编译选项会检查scanf对应的不定参数列表中提供的类型是否正确,因此会警告。不开启-Wall选项则不会检查是否正确,则不会警告。

区别

然而这样的写法虽然会引起编译的警告,但并不会导致编译错误,而且也不会引发程序运行的错误。

准确来说,在大部分实现上,二者达到的目的是一样的。
尽管在标准中,并不确保scanf提供参数类型错误时,也会得到正确的结果,但是由于实现的关系,往往能得到正确的结果。

但是这两种方法仍然是有微小的区别的,在我们将s[0]作为读入的第一个字符的时候,两者没有区别,但假如我们将s[1]作为读入的第一个字符,那它们将会出现不同的结果。

s[0]作为第一个字符

第一种写法

#include<cstdio>
char s[100];
int main() {scanf("%s",s);printf("%s",s);
}

运行结果正确:

在这里插入图片描述

第二种写法

#include<cstdio>
char s[100];
int main() {scanf("%s",&s);printf("%s",s);
}

运行结果正确:

在这里插入图片描述

以s[1]作为第一个字符

第一种写法

#include<cstdio>
char s[100];
int main() {scanf("%s",s+1);printf("%s",s+1);
}

运行结果正确:

在这里插入图片描述

第二种写法

#include<cstdio>
char s[100];
int main() {scanf("%s",&s+1);printf("%s",s+1);
}

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

这是实际上是发生了访问越界,可以放大一下访问倍数,就会报运行错误:

#include<cstdio>
char s[2000];
int main() {scanf("%s",&s+20);printf("%s",s+20);
}

运行错误:
在这里插入图片描述

具体区别

对于这个字符数组:

char s[10]{};

首先我们知道,s和&s在数值上确实是相等的,但是其指向的类型并不相同。
但是我们知道s+1与&s+1在数值上不一定是相等的:
可以用这个程序对比一下:

#include<iostream>
using namespace std;
int main() {char s[10]{};auto p=&s;cout<<p<<endl;cout<<p+1<<endl;cout<<endl;cout<<static_cast<void*>(s)<<endl;cout<<static_cast<void*>(s+1)<<endl;这里要用关键字static_cast将s的类型从char*转化为void*,是因为cout默认会将char*按照字符串格式输出,而不会选择输出一个地址这里不使用c风格强制类型转换主要是出于习惯
}

我们发现,s+1与s相差了1,而&s+1与&s却相差了10:

在这里插入图片描述

原因

要弄清楚这个问题的原因,就需要先了解清楚s和&s有什么区别。也就是数组名和数组名的地址有什么区别。

那么首先我们要知道,将普通变量+1后,其数值会增加1。但是将指针变量+1后,增加的值等于其指向的类型占用的字节数。
如果我们认为int是4个字节,那么也就是说:

int a[]={0,1};
int* p=a[0];
p++; 此时p数值增加了4,指向了a[1]的位置
此时 *p=1

同理,如果是char类型指针,那么+1后,其数值只会增加1,因为char类型只占用一个字节。

其次,我们需要知道计算机程序在运行中必须要跟踪的数据的三个信息:

  1. 变量被存储在哪里
  2. 变量的值是多少
  3. 变量的类型是什么

我们知道,数组名在C++中通常被看做是指向数组第一个元素的指针,也就是说,s被看做是一个指向s[0]位置的char类型指针,也就是char*。
(当然这个说法并不准确,事实上,s的类型在程序中被跟踪为一个“长度为10的字符数组”,但是s+1则只被识别为“指向s[1]位置的字符指针”)

使用typeid方法获得的类型信息:

这里的"A"表示“array”,是数组。
“10”表示数组长度。
“P”表示一个指针。
“c”表示“char”。
在这里插入图片描述

我们将s看作是指向数组第一个元素的指针,因此s+1比s增加了一个字节,也就是一个char类型的长度。

我们同样可以打出&s的类型:
在这里插入图片描述
这表明编译器认为&s是一个指向长度为10的字符数组的指针,因此&s+1与&s之间相差了10个字节。
指向数组的指针,这个类型十分复杂,以至于用常规方法很难只用一条语句就把它声明出来。
我想到三个方法可以把它声明出来:

  1. 可以使用decltype方法自动推导类型:
decltype(s) *p=&s;
  1. 可以使用auto方法自动推导类型:
auto p=&s;
  1. 可以使用多条语句来声明此类型
	typedef char T[10]; 先用typedef语句声明一个T类型,T类型是一个长度为10的字符数组T* p=&s; 			再声明一个T类型指针

后记

于是皆大欢喜。

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

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

相关文章

Jmeter-获取接口响应头(Response headers)信息进行关联

文章目录 Jmeter-获取接口响应头&#xff08;Response headers&#xff09;信息进行关联使用正则表达式提取器将Set-Cookie的值提取出来在其余接口中关联该提取信息运行查看关联是否成功 Jmeter-获取接口响应头&#xff08;Response headers&#xff09;信息进行关联 获取某一…

重发布选路最佳实验

题目 IP地址配置 R1&#xff1a; R2&#xff1a; R3&#xff1a; R4&#xff1a; 双点重发布 R2&#xff1a; rip 1 version 2 network 12.0.0.0 network 2.0.0.0 import-route ospf 1 ospf 1 import-route rip 1 route-policy R2 area 0.0.0.0 network 23.1.1.0 0.0…

ElasticSearch:环境搭建步骤

1、拉取镜像 docker pull elasticsearch:7.4.0 2、创建容器 docker run -id --name elasticsearch -d --restartalways -p 9200:9200 -p 9300:9300 -v /usr/share/elasticsearch/plugins:/usr/share/elasticsearch/plugins -e "discovery.typesingle-node" elasti…

腾讯云COS的快速接入

背景 最近在研究一个剪贴板粘贴工具&#xff0c;实现粘贴图片&#xff0c;返回可访问的地址&#xff0c;这个在我的哔哩哔哩上有出一期视频&#x1f92d;。但是&#xff0c;我发现部分博客平台不能正常的转载我的图片链接&#xff0c;于是研究了一下腾讯云的COS&#xff08;阿…

linux程序保护机制gcc编译选项

预备知识&#xff1a; 计算机内存的结构通常包括以下几个主要部分&#xff1a; 1.代码段(Code Segment)&#xff1a;也称为文本段&#xff0c;存储程序的可执行指令。代码段是被标记为可执行的&#xff0c;程序从代码段中获取指令并执行。 2.数据段(Data Segment)&#xff1a…

现代C++中的从头开始深度学习:【4/8】梯度下降

一、说明 在本系列中&#xff0c;我们将学习如何仅使用普通和现代C编写必须知道的深度学习算法&#xff0c;例如卷积、反向传播、激活函数、优化器、深度神经网络等。 在这个故事中&#xff0c;我们将通过引入梯度下降算法来介绍数据中 2D 卷积核的拟合。我们将使用卷积和上一个…

大数据技术之Hadoop:HDFS集群安装篇(三)

目录 分布式文件系统HDFS安装篇 一、为什么海量数据需要分布式存储 二、 分布式的基础架构分析 三、 HDFS的基础架构 四 HDFS集群环境部署 4.1 下载安装包 4.2 集群规划 4.3 上传解压 4.4 配置HDFS集群 4.5 准备数据目录 4.6 分发hadoop到其他服务器 4.7 配置环境变…

OpenStack监控工具

OpenStack是一个开源的云计算管理平台项目&#xff0c;是一系列软件开源项目的组合。由NASA和Rackspace合作研发并发起&#xff0c;以Apache许可证&#xff08;Apache软件基金会发布的一个自由软件许可证&#xff09;授权。 OpenStack为私有云和公有云提供可扩展的弹性的云计算…

Cadvisor+InfluxDB+Grafan+Prometheus(详解)

目录 一、CadvisorInfluxDBGrafan案例概述 &#xff08;一&#xff09;Cadvisor Cadvisor 产品特点&#xff1a; &#xff08;二&#xff09;InfluxDB InfluxDB应用场景&#xff1a; InfluxDB主要功能&#xff1a; InfluxDB主要特点&#xff1a; &#xff08;三&#…

·[K8S:使用calico网络插件]:解决集群节点NotReady问题

文章目录 一&#xff1a;安装calico&#xff1a;1.1&#xff1a;weget安装Colico网络通信插件&#xff1a;1.2&#xff1a;修改calico.yaml网卡相关配置&#xff1a;1.2.1&#xff1a;查看本机ip 网卡相关信息&#xff1a;1.2.2&#xff1a;修改calico.yaml网卡interface相关信…

深度解读|一站式ABI平台 Smartbi Insight V11 能力再升级

纵观过去&#xff0c;我们发现汽车和BI的发展有异曲同工之妙。 100来年&#xff0c;汽车的动力从蒸汽到燃油再到新能源&#xff0c;汽车的操控方式从手动到自动再到智能无人驾驶。而在BI领域&#xff0c;自1958年BI的概念提出后&#xff0c;底层数据准备从报表开发、Cube多维模…

【CI/CD】Git Flow 分支模型

Git Flow 分支模型 1.前言 Git Flow 模型&#xff08;本文所阐述的分支模型&#xff09;构思于 2010 年&#xff0c;也就是 Git 诞生后不久&#xff0c;距今已有 10 多年。在这 10 多年中&#xff0c;Git Flow 在许多软件团队中大受欢迎。 在这 10 多年里&#xff0c;Git 本身…

最大子数组和【力扣53】

一、解题思路 Max[i]表示&#xff1a;以nums[i]为开头的所有连续子数组和的最大值。 由此可以推出Max[i-1]和Max[i]的关系&#xff1a; 若Max[i]>0&#xff1a;Max[i-1]nums[i-1]Max[i]&#xff1b; 否则&#xff1a;Max[i-1]nums[i-1]&#xff1b; 则ansMAX&#xff0…

RISC-V走向开放服务器规范

原文&#xff1a;RISC-V Moving Toward Open Server Specification 作者&#xff1a;Agam Shah 转载自&#xff1a;https://www.hpcwire.com/2023/07/24/risc-v-moving-toward-open-server-specification/ 中文翻译&#xff1a; 2023年7月24日 RISC-V International目前正…

亚马逊 EC2服务器下部署java环境

1. jdk 1.8 安装 1.1 下载jdk包 官网 Java Downloads | Oracle tar.gz 包 下载下来 1.2 本地连接 服务器 我用的是亚马逊的ec2 系统是 ubuntu 的 ssh工具是 Mobaxterm , 公有dns 创建实例时的秘钥 链接 Mobaxterm 因为使用的 ubuntu 所以登录的 名称 就是 ubuntu 然后 …

【Ubuntu】简化反向代理和个性化标签页体验

本文将介绍如何使用Docker部署Nginx Proxy Manager和OneNav&#xff0c;两个功能强大且易用的工具。Nginx Proxy Manager用于简化和管理Nginx反向代理服务器的配置&#xff0c;而OneNav则提供个性化的新标签页体验和导航功能。通过本文的指导&#xff0c;您将学习如何安装和配置…

程序使用Microsoft.XMLHTTP对象请求https时出错解决

程序中使用Microsoft.XMLHTTP组件请求https时出现如下错误&#xff1a; 出错程序代码示例&#xff1a; strUrl "https://www.xxx.com/xxx.asp?id11" dim objXmlHttp set objXmlHttp Server.CreateObject("Microsoft.XMLHTTP") objXmlHttp.open "…

Cesium相机理解

关于cesium相机&#xff0c;包括里面内部原理网上有很多人讲的都很清楚了&#xff0c;我感觉这两个人写的都挺好得&#xff1a; 相机 Camera | Cesium 入门教程 (syzdev.cn) Cesium中的相机—setView&lookAtTransform_cesium setview_云上飞47636962的博客-CSDN博客上面这…

【Linux】进程间通信——system V共享内存

目录 写在前面的话 System V共享内存原理 System V共享内存的建立 代码实现System V共享内存 创建共享内存shmget() ftok() 删除共享内存shmctl() 挂接共享内存shmat() 取消挂接共享内存shmdt() 整体通信流程的实现 写在前面的话 上一章我们讲了进程间通信的第一种方式…

Linux基础学习

文章目录 Linux命令学习Linux环境准备Linux命令行学习Linux命令行格式与文件系统linux实用命令笔记Linux文件权限查看 Linux命令学习 理解Linux命令是什么 &#xff08;图形化的操作&#xff0c;文件查看&#xff0c;浏览器打开&#xff09; 你打开一个谷歌浏览器&#xff0c;…