数组和指针笔试题解析之【数组】

目录

前言:

1.一维数组:

2.字符数组 :

2.1题型一:

2.2题型二: 

2.3题型三: 

3.二维数组 :


前言:

1.数组名的意义:

  • sizeof(数组名):这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
  • &数组名:这里的数组名表示整个数组,取出的是整个数组的地址。
  • 除此之外所有的数组名都表示首元素的地址。

2.地址在内存中唯一标识一块空间,大小是4/8个字节。在32位平台下(X86环境)是4字节,64位平台下(X64环境)是8字节。

3.sizeof操作符,计算的是对象或者类型创建的对象所占内存空间的大小,单位是字节,它不会关注内存中存放的到底是什么。

4.strlen库函数,求的是字符串长度,本质上是统计字符串中\0之前出现的字符个数。

1.一维数组:

int main()
{int a[] = { 1,2,3,4 };printf("%d\n", sizeof(a));printf("%d\n", sizeof(a + 0));printf("%d\n", sizeof(*a));printf("%d\n", sizeof(a + 1));printf("%d\n", sizeof(a[1]));printf("%d\n", sizeof(&a));printf("%d\n", sizeof(*&a));printf("%d\n", sizeof(&a + 1));printf("%d\n", sizeof(&a[0]));printf("%d\n", sizeof(&a[0] + 1));return 0;
}

运行结果: 

🎈解析: 

printf("%d\n",sizeof(a));

数组名a单独放在sizeof内部,数组名表示整个数组,计算的是整个数组的大小,单位是字节,所以是16字节 


printf("%d\n",sizeof(a[0][0]));

a并非单独放在sizeof内部,也没有&,所以数组名是数组首元素的地址,即a+0还是首元素的地址,是地址大小就是4/8字节  


printf("%d\n", sizeof(*a));

a并非单独放在sizeof内部,也没有&,所以数组名是数组首元素的地址,*a就是首元素,也可以写成*a == *(a+0) == a[0],大小就是4字节


printf("%d\n", sizeof(a + 1));

a并非单独放在sizeof内部,也没有&,所以数组名是数组首元素的地址,a+1就是第二个元素的地址,a+1 == &a[1],是第二个元素的地址,是地址大小就是4/8字节 


printf("%d\n", sizeof(a[1]));

a[1]就是数组的第二个元素,这里计算的就是第二个元素的大小,单位是字节,为4字节 


printf("%d\n", sizeof(&a));

&a是取出数组的地址,但是数组的地址也是地址,是地址就是4/8个字节,数组的地址和数组首元素的地址的本质区别是类型的区别,并非大小的区别

a    ---  int*                      int * p = a;

&a  ---  int (*)[4]            int (*p)[4] = &a; 


printf("%d\n", sizeof(*&a));

1.对数组指针解引用访问一个数组的大小,单位是字节,所以是16字节

2.还可以理解为sizeof(*&a) 等价于 sizeof(a)


printf("%d\n", sizeof(&a + 1));

&a是数组的地址,&a+1还是地址,是地址就是4/8个字节 


printf("%d\n", sizeof(&a[0]));

&a[0]就是取出首元素的地址,计算的是地址的大小,就是4/8个字节 


printf("%d\n", sizeof(&a[0] + 1));

&a[0]是首元素的地址,&a[0] + 1就是第二个元素的地址,大小是4/8个字节

&a[1] 、&a[0] + 1、a+1都可以取出第二个元素的地址 

2.字符数组 :

2.1题型一:

int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr+0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr+1));printf("%d\n", sizeof(&arr[0]+1));return 0;
}

运行结果: 

🎈解析: 

printf("%d\n", sizeof(arr));

 数组名arr单独放在sizeof内部,计算的是整个数组的大小,就是6字节


printf("%d\n", sizeof(arr+0));

arr是首元素的地址==&arr[0],是地址就是4/8个字节

注意:

       1. 指针变量的大小和类型无关,不管什么类型的指针变量,大小都是4/8个字节

        2.指针变量是用来存放地址的,地址存放需要多大空间,指针变量的大小就是几个字节

        3.32位环境下,地址是32个二进制位,需要4个字节,所以指针变量的大小就是4个字节

        4.64位环境下,地址是64个二进制位,需要8个字节,所以指针变量的大小就是8个字节

        💘不要门缝里看指针,把指针看扁喽


printf("%d\n", sizeof(*arr));

arr是首元素的地址,*arr就是首元素,大小就是1字节 


printf("%d\n", sizeof(arr[1]));

arr[1]是首元素,大小就是1字节 


printf("%d\n", sizeof(&arr));

&arr是数组的地址,大小就是4/8个字节 


printf("%d\n", sizeof(&arr+1));

&arr+1是跳过数组后的地址,是地址就是4/8个字节 


printf("%d\n", sizeof(&arr[0]+1));

&arr[0]是第一个元素的地址,+1就是第二个元素的地址,是地址就是4/8个字节 


🎈下面我们将这个代码稍微变动一下,将sizeof变为strlen,我们再来分析一下 :

注:strlen函数求的是字符串长度,统计的是在字符串中\0之前出现的字符的个数

#include <string.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };//末尾没有\0printf("%d\n", strlen(arr));printf("%d\n", strlen(arr + 0));//printf("%d\n", strlen(*arr));//err//printf("%d\n", strlen(arr[1]));//errprintf("%d\n", strlen(&arr));printf("%d\n", strlen(&arr + 1));printf("%d\n", strlen(&arr[0] + 1));return 0;
}

运行结果: 

🎈解析: 

printf("%d\n", strlen(arr));

arr是首元素的地址,从首元素向后找,找不到\0,所以它的长度就为随机值 


printf("%d\n", strlen(arr+0));

 arr是首元素的地址,arr+0还是首元素的地址,所以它的长度也为随机值


printf("%d\n", strlen(*arr));

  arr是首元素的地址,*arr就是首元素-> 'a' -> 97,站在strlen的角度,认为传参进去的 'a' -> 97就是地址,97作为地址,直接进行访问,就是非法访问,所以这是一个错误代码


printf("%d\n", strlen(arr[1]));

arr[1]就是第二个元素 'b' -> 98,98作为地址,直接进行访问,就是非法访问,所以这也是一个错误代码


printf("%d\n", strlen(&arr));

&arr取出的类型是char (*)[6](数组指针类型),strlen 的类型是const char*,将&arr的类型传给strlen类型必然会进行类型的转换,编译器会报警告,但是传参的时候只是类型发生了变化,值不变,所以还是从第一个元素开始向后找,找不到\0,它的长度也为随机值


printf("%d\n", strlen(&arr+1));

&arr取出的是整个数组的地址,+1跳过整个数组,向后找还是找不到\0,所以它的长度也为随机值 


printf("%d\n", strlen(&arr[0]+1));

&arr[0]取出的是第一个元素的地址,+1后指向第二个元素,从第二个元素向后还是找不到\0,所以它的长度也为随机值 


2.2题型二: 

int main()
{char arr[] = "abcdef";//a b c d e f \0printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr + 0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr + 1));printf("%d\n", sizeof(&arr[0] + 1));return 0;
}

运行结果: 

🎈解析: 

printf("%d\n", sizeof(arr));

sizeof(arr)计算的是整个数组的大小,加上\0为7个字节 


printf("%d\n", sizeof(arr+0));

arr是首元素的地址,加0还是首元素的地址,是地址大小就为4/8个字节 


printf("%d\n", sizeof(*arr));

arr是数组名,是首元素的地址,给它解引用就是首元素 'a' ,它的大小就是1个字节 


printf("%d\n", sizeof(arr[1]));

arr[1]就是第二个元素,它的大小也是1字节 


printf("%d\n", sizeof(&arr));

&arr取出的是数组的地址,数组的地址也是地址,是地址就是4/8个字节 


printf("%d\n", sizeof(&arr+1));

 &arr取出的是数组的地址,加1跳过整个数组,还是地址,大小就是4/8个字节


printf("%d\n", sizeof(&arr[0]+1));

&arr[0]是第一个元素的地址,加1就是第二个元素的地址,是地址就是4/8个字节 


 🎈下面我们再来将这个代码变动一下,将sizeof变为strlen

#include <string.h>int main()
{char arr[] = "abcdef";printf("%d\n", strlen(arr));printf("%d\n", strlen(arr + 0));//printf("%d\n", strlen(*arr));//err//printf("%d\n", strlen(arr[1]));///errprintf("%d\n", strlen(&arr));printf("%d\n", strlen(&arr + 1));printf("%d\n", strlen(&arr[0] + 1));return 0;
}

运行结果: 

🎈解析: 

printf("%d\n", strlen(arr));

arr是数组名,即首元素地址,从首元素向后数,统计\0之前的字符,长度为6 


printf("%d\n", strlen(arr+0));

 arr是数组名,为首元素地址,加0还是首元素地址,从首元素向后数,统计\0之前的字符,长度也为6 


printf("%d\n", strlen(*arr));

 arr是首元素地址,对首元素地址解引用得到的就是首元素,传给strlen的就是字符'a',即97,所以这是个错误代码


printf("%d\n", strlen(arr[1]));

arr[1]是这个数组的第二个元素,即把字符'b'传了进去,所以它也是个错误代码 


printf("%d\n", strlen(&arr));

&arr取出的是整个数组的地址,但它也是从a向后数,直到\0截至,所以它的长度为6 


printf("%d\n", strlen(&arr+1));

&arr+1是跳过整个数组,包括后边的\0,从\0后边开始数,不确定什么时候会遇到\0,所以它的长度为随机值 


printf("%d\n", strlen(&arr[0]+1));

&arr[0]+1得到的是第二个元素的地址,从第二个元素开始向后数,得到的长度就是5 


2.3题型三: 

int main()
{//把字符串首字符的地址放到了p里边去,也就是说p指向了"abcdef"char* p = "abcdef";printf("%d\n", sizeof(p));printf("%d\n", sizeof(p + 1));printf("%d\n", sizeof(*p));printf("%d\n", sizeof(p[0]));printf("%d\n", sizeof(&p));printf("%d\n", sizeof(&p + 1));printf("%d\n", sizeof(&p[0] + 1));return 0;
}

运行结果: 

🎈解析: 

printf("%d\n", sizeof(p));

 p是一个指针变量,计算的就是指针变量的大小,就是4/8字节


printf("%d\n", sizeof(p+1));

p是一个char*的指针,+1向后偏移一个字节,但它本质上还是一个地址,大小是4/8个字节 


printf("%d\n", sizeof(*p));

 p是char*的指针,解引用访问一个字节,所以它的大小就是1字节


printf("%d\n", sizeof(p[0]));

p[0] ---> *(p+0) ---> *p == 'a',所以它的大小也是1字节


printf("%d\n", sizeof(&p));

&p也是地址(指针变量p的起始地址),大小也是4/8个字节 


printf("%d\n", sizeof(&p+1));

&p是地址,&p+1还是地址,是地址就是4/8个字节 


printf("%d\n", sizeof(&p[0]+1));

&p[0]是第一个元素的地址,&p[0]+1就是第二个元素的地址,大小就是4/8个字节 


🎈 将sizeof变为strlen,我们继续分析:

int main()
{char* p = "abcdef";//a b c d e f \0printf("%d\n", strlen(p));printf("%d\n", strlen(p + 1));printf("%d\n", strlen(*p));printf("%d\n", strlen(p[0]));printf("%d\n", strlen(&p));printf("%d\n", strlen(&p + 1));printf("%d\n", strlen(&p[0] + 1));return 0;
}

🎈解析: 

printf("%d\n", strlen(p));

 p指向了字符串中的首字符'a',从a向后数,截至到\0,长度就为6


printf("%d\n", strlen(p + 1));

p+1跳过一个字节,从第二个元素向后数,长度就是5 


printf("%d\n", strlen(*p));

p指向字符串中第一个元素的位置,解引用就是'a',所以这是个错误代码 


printf("%d\n", strlen(p[0]));

p[0]也是第一个元素,传给strlen的也是'a'的ASCII码值,错误代码 


printf("%d\n", strlen(&p));

 &p指向了指针变量p的起始地址,在这个内存里边有没有\0以及什么时候遇到\0完全是不可知的,所以它的长度就是一个随机值


printf("%d\n", strlen(&p + 1));

&p+1是跳过p,指向的下一块内存后续空间有什么也是不可知的,所以它的长度也是随机值 


printf("%d\n", strlen(&p[0] + 1));

 &p[0]+1就是第二个元素的地址,从第二个元素向后数长度就是5

3.二维数组 :

二维数组在内存中的存放形式为:

但我们平常可以将它的存放理解成这样: 

🎈注意:一维数组的数组名通常表示首元素的地址,二维数组的数组名通常表示第一行的地址。二维数组的数组名单独放在sizeof内部表示整个数组。 

int main()
{int a[3][4] = { 0 };printf("%zd\n", sizeof(a));printf("%zd\n", sizeof(a[0][0]));printf("%zd\n", sizeof(a[0]));printf("%zd\n", sizeof(a[0] + 1));printf("%zd\n", sizeof(*(a[0] + 1)));printf("%zd\n", sizeof(a + 1));printf("%zd\n", sizeof(*(a + 1)));printf("%zd\n", sizeof(&a[0] + 1));printf("%zd\n", sizeof(*(&a[0] + 1)));printf("%zd\n", sizeof(*a));printf("%zd\n", sizeof(a[3]));return 0;
}

 运行结果:

🎈解析: 

printf("%zd\n", sizeof(a));

数组名a单独放在了sizeof 内部,表示整个数组,sizeof(a)计算的是数组的大小,单位是字节,所以它的大小就是3x4x12=48字节


printf("%zd\n", sizeof(a[0][0]));

a[0][0] 是数组的第一行第一个元素,这里计算的就是一个元素的大小,所以是4字节


printf("%zd\n", sizeof(a[0]));

a[0]是第一行这个一维数组的数组名,数组名单独放在sizeof内部,a[0]就表示整个第一行这个一维数组,sizeof(a[0])计算的整个第一行这个一维数组的大小就为4x4=16字节


printf("%zd\n", sizeof(a[0] + 1));

a[0]并非单独放在sizeof内部,也没有&, a[0]就表示第一行这个一维数组首元素的地址,也就是第一行第一个元素的地址,+1表示第一行第二个元素的地址,是地址就是4/8个字节


printf("%zd\n", sizeof(*(a[0] + 1)));

a[0]+1表示第一行这个一维数组第二个元素的地址,对其进行解引用操作,得到第一行第二个元素,所以大小为4字节 


printf("%zd\n", sizeof(a + 1));

a作为二维数组的数组名,并没有单独放在sizeof内部,也没有&,那a就是数组首元素的地址,也就是第一行的地址,类型是int(*)[4],a+1就是第二行的地址,大小为4/8字节


printf("%zd\n", sizeof(*(a + 1)));

a+1表示第二行的地址,对其解引用,就表示整个第二行数组的大小,为16字节 


printf("%zd\n", sizeof(&a[0] + 1));

 a[0]是第一行的数组名,&a[0]取出的就是第一行这个一维数组的地址,类型为int (*)[4],+1就是第二行的地址,是地址大小就为4/8字节


printf("%zd\n", sizeof(*(&a[0] + 1)));

*(&a[0] + 1)得到的是第二行,计算的就是第二行的大小,为16字节


printf("%zd\n", sizeof(*a));

a表示数组首元素的地址,也就是第一行的地址,*a就是第一行,相当于第一行的数组名,大小就为16字节 


	printf("%zd\n", sizeof(a[3]));

 表达式有两个属性:1.值属性   2.类型属性;a[3]是二维数组的第四行,虽然这个数组没有第四行,但是它的类型能够确定,大小就是确定的,所以为16字节

 

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

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

相关文章

【C++STL基础入门】list的运算符重载和关于list的算法

文章目录 前言一、list运算符1.1 逻辑运算符1.2 赋值运算符 二、list相关算法2.1 查找函数总结 前言 C标准模板库&#xff08;STL&#xff09;是一组强大而灵活的工具&#xff0c;用于处理数据结构和算法。其中&#xff0c;std::list是STL中的一个重要容器&#xff0c;它实现了…

小型网络实验组网

路漫漫其修远兮&#xff0c;吾将上下而求索 时隔多日&#xff0c;没有更新&#xff0c;今日一写&#xff0c;倍感教育的乐趣。如果让我每天发无意义的文章&#xff0c;我宁可不发。 实验拓扑 实验要求 &#xff08;1&#xff09;内网主机采用DHCP分配IP地址 &#xff08;2&…

记录本地Nginx发布vue项目

一、前端&#xff1a;vue-cli-service build 二、下载Nginx&#xff0c;并创建目录&#xff0c;放置静态文件 三、在conf目录下nginx.conf文件配置代理服务 server {listen 8787;server_name localhost;location / {root app/dist; #前端dist包地址index index.html…

Tomcat架构设计及组件详解

继Tomcat配置详解&#xff08;Tomcat配置server.xml详解&#xff09;Tomcat配置详解&#xff08;Tomcat配置server.xml详解&#xff09;_tomcat xml配置https://blog.csdn.net/imwucx/article/details/132166738文章之后&#xff0c;深入的学习tomcat相关知识&#xff0c;对Tom…

基于SSM+Vue的“魅力”繁峙宣传网站

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

数据分享|R语言逻辑回归、Naive Bayes贝叶斯、决策树、随机森林算法预测心脏病...

全文链接&#xff1a;http://tecdat.cn/?p23061 这个数据集&#xff08;查看文末了解数据免费获取方式&#xff09;可以追溯到1988年&#xff0c;由四个数据库组成。克利夫兰、匈牙利、瑞士和长滩。"目标 "字段是指病人是否有心脏病。它的数值为整数&#xff0c;0无…

无代码和低代码平台:程序员的竞争优势

无代码和低代码平台&#xff1a;程序员的竞争优势 无代码和低代码平台&#xff1a;程序员的竞争优势摘要引言1. 了解无代码和低代码平台1.1 无代码和低代码平台的定义无代码平台低代码平台 1.2 它们如何简化应用程序开发1.3 主要的无代码和低代码工具和供应商无代码平台低代码…

【八大经典排序算法】堆排序

【八大经典排序算法】堆排序 一、概述二、思路解读三、代码实现&#xff08;大堆为例&#xff09; 一、概述 堆排序是J.W.J. Williams于1964年提出的。他提出了一种利用堆的数据结构进行排序的算法&#xff0c;并将其称为堆排序。堆排序是基于选择排序的一种改进&#xff0c;通…

蓝牙核心规范(V5.4)10.1-BLE 入门笔记(1)

ble 规范 深入了解蓝牙LE需要熟悉相关的规格。蓝牙LE的架构、程序和协议由一项关键规范完全定义,称为蓝牙核心规范。产品如何使用蓝牙以实现互操作性由两种特殊类型称为配置文件和服务的规范集合所涵盖。图1展示了BLE规范类型及其相互关系。 1.1 蓝牙核心规范 蓝牙核心规范是…

SpringBoot整合Easy-ES实现对ES操作

请确保已有可用的ES&#xff0c;若没有&#xff0c;请移步&#xff1a;Docker安装部署ElasticSearch&#xff08;ES&#xff09; 新建SpringBoot项目 这里是用的springboot版本是2.6.0 引入依赖 <!-- 排除springboot中内置的es依赖,以防和easy-es中的依赖冲突--><…

Redis五大基本数据类型

1、字符串类型 字符串类型相当于 java 中的 String 类型。Redis 中的 String 类型以二进制方式存储&#xff0c;不会做任何的编码转换&#xff0c;因此不仅仅可以存储文本数据、整数、普通的字符串、JSON、xml文件&#xff0c;还可以存储图片、视频、音频。String 存储的种类虽…

插槽指的是什么?插槽的基础用法体验

什么是插槽 插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时&#xff0c;把不确定的、希望由用户指定的部分定义为插槽。 <template><p>这是MyCom1组件的第1个p标签</p><&#xff01;--通过slot标签&#xff0c;为用户预留内容占位符…

Vue3 Ajax(axios)异步

文章目录 Vue3 Ajax(axios)异步1. 基础1.1 安装Ajax1.2 使用方法1.3 浏览器支持情况 2. GET方法2.1 参数传递2.2 实例 3. POST方法4. 执行多个并发请求5. axios API5.1 传递配置创建请求5.2 请求方法的别名5.3 并发5.4 创建实例5.5 实例方法5.6 请求配置项5.7 响应结构5.8 配置…

jvm的调优工具

1. jps 查看进程信息 2. jstack 查看进程的线程 59560为进程id 产生了死锁就可以jstack查看了 详细用途可以看用途 3. jmap 如何使用dump文件看下 查看 4.jstat 空间占用和次数 5. jconsole可视化工具 各种使用情况&#xff0c;以及死锁检测 6. visualvm可视化工具…

SpringMVC自定义注解---[详细介绍]

一&#xff0c;对于SpringMVC自定义注解概念 是一种特殊的 Java 注解&#xff0c;它允许开发者在代码中添加自定义的元数据&#xff0c;并且可以在运行时使用反射机制来获取和处理这些信息。在 Spring MVC 中&#xff0c;自定义注解通常用于定义控制器、请求处理方法、参数或者…

面试题四:请解释一下watch,computed和filter之间的区别

watch与computed、filter&#xff1a; watch:监控已有属性&#xff0c;一旦属性发生了改变就去自动调用对应的方法 computed:监控已有的属性,一旦属性的依赖发生了改变&#xff0c;就去自动调用对应的方法.computed有详细的介绍&#xff0c;移步computed的使用 filter:js中为…

MATLAB中filloutliers函数用法

目录 语法 说明 示例 在向量中对离群值进行插值 使用均值检测和最邻近值填充方法 使用移窗检测法 填充矩阵行中的离群值 指定离群值位置 返回离群值阈值 filloutliers函数功能是检测并替换数据中的离群值。 语法 B filloutliers(A,fillmethod) B filloutliers(A,f…

聚观早报 | iPhone 15系列正式发布;月饼专利申请超10000项

【聚观365】9月14日消息 iPhone 15系列正式发布 月饼专利申请超10000项 “五个女博士”自建研究院 2023中国民营企业研发十强公布 华为和小米达成全球专利交叉许可协议 iPhone 15系列正式发布 2023年苹果秋季新品发布会如期而至。发布会上&#xff0c;苹果发布了iPhone 1…

STM32 CAN使用记录:FDCAN基础通讯

文章目录 目的基础说明关键配置与代码轮询方式中断方式收发测试 示例链接总结 目的 CAN是非常常用的一种数据总线&#xff0c;被广泛用在各种车辆系统中。这篇文章将对STM32中FDCAN的使用做个示例。 CAN的一些基础介绍与使用可以参考下面文章&#xff1a; 《CAN基础概念》htt…

基于Xml方式Bean的配置-Bean的延时加载

SpringBean的配置详解 Bean的延时加载 当lazy-init设置为true时为延时加载&#xff0c;也就是当Spring容器创建的时候&#xff0c;不会立即创建Bean实例&#xff0c;等待用到时再创建Bean实例并储存到单例池中&#xff0c;后续使用该Bean时直接从单例池中获取即可&#xff0c;…