【进阶C语言】数组笔试题解析

本节内容以刷题为主,大致目录:

1.一维数组

2.字符数组

3.二维数组

学完后,你将对数组有了更全面的认识


在刷关于数组的题目前,我们先认识一下数组名:

数组名的意义:表示数组首元素的地址

但是有两个例外:

(1)sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。单位:字节。

(2)&数组名,这里的数组名表示整个数组,取出的是整个数组的大小。 

一、一维数组

1.判断下列sizeof计算的大小

(1)一维数组

#include<stdio.h>
int main()
{
	int a[] = { 1,2,3,4 };//一维数组
	printf("%zd\n", sizeof(a));
	printf("%zd\n", sizeof(a + 0));
	printf("%zd\n", sizeof(*a));
	printf("%zd\n", sizeof(a + 1));
	printf("%zd\n", sizeof(a[1]));
	printf("%zd\n", sizeof(&a));
	printf("%zd\n", sizeof(*&a));
	printf("%zd\n", sizeof(&a + 1));
	printf("%zd\n", sizeof(&a[0]));
	printf("%zd\n", sizeof(&a[0] + 1));
	return 0;
}

结果展示:

代码分析:

#include<stdio.h>
int main()
{
	int a[] = { 1,2,3,4 };//一维数组
	//整形数组,每个元素4个字节,整个数组为16字节

	printf("%zd\n", sizeof(a));
	//数组名直接放在sizeof内部,表示整个数组的大小

	printf("%zd\n", sizeof(a + 0));
	//数组名没有单独放在sizeof内部,表示数组首元素的地址。大小就是4/8字节

	printf("%zd\n", sizeof(*a));
	//a就是首元素地址。*a==*(a+0)==a[0];所以*a就算首元素,大小为4字节

	printf("%zd\n", sizeof(a + 1));
	//a为首元素地址,+1跳过一个元素的地址,就算第二个元素的地址。a+1==&a[1]
	//只要是地址,就算4/8字节

	printf("%zd\n", sizeof(a[1]));
	//a[1]表示第二个元素,大小就是4字节

	printf("%zd\n", sizeof(&a));
	//&a,取出的是地址,只要是地址,就是4/8字节

	printf("%zd\n", sizeof(*&a));
	//*与&操作相互抵消。sizeof(*&a)==sizeof(a),为整个数组元素的大小==16字节
	
	printf("%zd\n", sizeof(&a + 1));
	//&a的结果是地址,+1操作后还是地址,那就是4/8字节

	printf("%zd\n", sizeof(&a[0]));
	//a[0]是第一个元素,&a[0]表示取出第一个元素的地址,地址就算4/8字节

	printf("%zd\n", sizeof(&a[0] + 1));
	//&a[0]是首元素的地址,&a[0]+1就是第二个元素的地址,大小4/8个字节

	return 0;
}

 内存分局图:

总结:只要可以确定是地址,那么大小一定就是4/8字节

(2)字符数组

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

结果展示:

代码分析:

#include<stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	//字符数组,每个元素大小1字节,整个数组大小6字节

	printf("%zd\n", sizeof(arr));
	//计算的是整个数组的大小,为6字节

	printf("%zd\n", sizeof(arr + 0));
	//计算的是地址,大小为4/8字节

	printf("%zd\n", sizeof(*arr));
	//*arr为第一个元素,大小为1字节

	printf("%zd\n", sizeof(arr[1]));
	//arr[1]表示第二个元素,大小为1字节

	printf("%zd\n", sizeof(&arr));
	//地址,4/8字节

	printf("%zd\n", sizeof(&arr + 1));
	//地址,4/8字节
	
	printf("%zd\n", sizeof(&arr[0] + 1));
	//地址,4/8字节

	return 0;
}

内存布局图:

(3)字符串数组

#include<stdio.h>
int main()
{
	char arr[] = "abcdef";
	printf("%zd\n", sizeof(arr));
	printf("%zd\n", sizeof(arr + 0));
	printf("%zd\n", sizeof(*arr));
	printf("%zd\n", sizeof(arr[1]));
	printf("%zd\n", sizeof(&arr));
	printf("%zd\n", sizeof(&arr + 1));
	printf("%zd\n", sizeof(&arr[0] + 1));
	return 0;
}

结果展示:

代码分析:

#include<stdio.h>
int main()
{
	char arr[] = "abcdef";
	//arr中的内容:a,b,c,d,e,f,\0

	printf("%zd\n", sizeof(arr));
	//整个数组大小:7字节

	printf("%zd\n", sizeof(arr + 0));
	//地址,4/8字节

	printf("%zd\n", sizeof(*arr));
	//首元素,1字节大小

	printf("%zd\n", sizeof(arr[1]));
	//第二个元素,1字节大小

	printf("%zd\n", sizeof(&arr));
	//地址,4/8字节

	printf("%zd\n", sizeof(&arr + 1));
	//地址,4/8字节

	printf("%zd\n", sizeof(&arr[0] + 1));
	//地址。4/8字节

	return 0;
}

内存分布图:

(4)单单字符串

char *p = "abcdef";
printf("%zd\n", sizeof(p));
printf("%zd\n", sizeof(p+1));
printf("%zd\n", sizeof(*p));
printf("%zd\n", sizeof(p[0]));
printf("%zd\n", sizeof(&p));
printf("%zd\n", sizeof(&p+1));
printf("%zd\n", sizeof(&p[0]+1));

结果展示:

代码分析:

#include<stdio.h>
int main()
{
	char* p = "abcdef";
	//p指向a的地址

	printf("%zd\n", sizeof(p));
	//p是指针,存放首字符a的地址,4/8字节

	printf("%zd\n", sizeof(p + 1));
	//p+1为字符b的地址,4/8字节

	printf("%zd\n", sizeof(*p));
	//*p==p[0],拿到的是第一个字符:a,为1字节

	printf("%zd\n", sizeof(p[0]));
	//求的是字符的大小,1字节

	printf("%zd\n", sizeof(&p));
	//地址,4/8字节

	printf("%zd\n", sizeof(&p + 1));
	//地址,4/8字节

	printf("%zd\n", sizeof(&p[0] + 1));
	//地址,4/8字节

	return 0;
}

内存分布图:

2.判断下列strlen计算的大小

知识点:strlen是计算字符串的长度(个数)的函数。统计的是在字符串中\0之前出现的字符的个数

(1)不带\0的字符数组

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

	return 0;
}

因为\0是strlen结束的标志,没有\0则不能正常计算

所以准确的来说,上述代码都是错误的。

错误原因解析:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));
	//随机值。地址

	printf("%d\n", strlen(arr + 0));
	//随机值。地址

	printf("%d\n", strlen(*arr));
	//非法访问地址,代码错误

	printf("%d\n", strlen(arr[1]));
	//非法访问地址,错误代码
	
	printf("%d\n", strlen(&arr));
	//随机值。地址

	printf("%d\n", strlen(&arr + 1));
	//随机值。地址

	printf("%d\n", strlen(&arr[0] + 1));
	//随机值。地址

	return 0;
}

内存分布图: 

(2)自带\0的字符串数组

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

代码分析:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abcdef";
	//arr中的数据:a,b,c,d,e,f,\0

	printf("%d\n", strlen(arr));
	//从起始位置开始计算长度,为6

	printf("%d\n", strlen(arr + 0));
	//从起始位置开始计算长度,为6

	printf("%d\n", strlen(*arr));
	//*arr==a,传入的值就为97,代码报错

	printf("%d\n", strlen(arr[1]));
	//arr[1]==b,传入的值为98,代码错误

	printf("%d\n", strlen(&arr));
	//从起始位置开始计算,长度为6

	printf("%d\n", strlen(&arr + 1));
	//&arr为起始地址,&arr+1跳过了整个数组,为随机值

	printf("%d\n", strlen(&arr[0] + 1));
	//从第二个元素开始,为5

	return 0;
}

内存分布图:

(3)带\0的纯字符串

#include<stdio.h>
#include<string.h>
int main()
{
	char* p = "abcdef";
	printf("%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;
}

代码分析:

#include<stdio.h>
#include<string.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", strlen(p));
	//从起始位置开始计算长度,为6

	printf("%d\n", strlen(p + 1));
	//从b位置开始计算长度,为5

	printf("%d\n", strlen(*p));
	//*p==a,传入97,代码报错

	printf("%d\n", strlen(p[0]));
	//代码报错

	printf("%d\n", strlen(&p));
	//&p为指针变量的地址,为随机值

	printf("%d\n", strlen(&p + 1));
	//&p+1跳过了该字符串,为随机值

	printf("%d\n", strlen(&p[0] + 1));
	//从b位置开始计算,长度为5

	return 0;
}

内存分布图:

二、二维数组

前言:二维数组的数组名同样是首元素地址,不过二维数组的首元素是第一行元素;而且依旧有两个例外。

题目:判断下列sizeof计算的大小

#include<stdio.h>
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;
}

运行结果:

代码分析:

#include<stdio.h>
int main()
{
	int a[3][4] = { 0 };
	//三行四列,一行的大小是12,整个数组是48

	printf("%zd\n", sizeof(a));
	//数组名单独放在里面,计算的是整个数组的大小

	printf("%zd\n", sizeof(a[0][0]));
	//a[0][0]表示第一行第一列的元素,计算的是元素的大小,4字节

	printf("%zd\n", sizeof(a[0]));
	//a[0]表示第一行的地址,也可以称为第一行这个数组的数组名
	//sizeof(arr[0])计算的就是第一行整个一维数组的全部大小,16字节

	printf("%zd\n", sizeof(a[0] + 1));
	//a[0]没有单独存放,a[0]==&a[0][0],也表示第一行第一个元素的地址
	//所以a[0]+1==&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+1是第二行的地址,4/8字节

	printf("%zd\n", sizeof(*(a + 1)));
	//a+1为第二行的地址,*(a+1)就是第二行
	//*(a+1)==a[1],第二行元素的总大小=4*4=16

	printf("%zd\n", sizeof(&a[0] + 1));
	//&a[0]是第一行的地址,&a[0]+1是第二行的地址
	//地址就是4/8字节

	printf("%zd\n", sizeof(*(&a[0] + 1)));
	//*(&a[0]+1)==a[1],计算的是第二行元素的大小,为16字节

	printf("%zd\n", sizeof(*a));
	//a没有单独放在sizeof内部,所以是第一行的地址
	//*a==a[0],计算的是第一行的元素,为16字节

	printf("%zd\n", sizeof(a[3]));
	//a[3]表示第四行元素,但是没有第四行元素
	//sizeof计算的只是类型大小,a[3]和a[0]或a[1]一样,都表示某一行元素
	//虽然没有第四行,但是跟a[0]的类型一样,都是四个int元素的数组

	return 0;
}

内存布局图:

总结:有二维数组a[3][4]

(1)a、a[0]、a[1]、a[2]都表示数组名

(2)a是二维数组的数组名,a[0]、a[1]、a[2]分别是第一、二、三行的数组名。

(3)第一、第二和第三行数组又可以称为一个一维数组

(4)a、a[0]、a[1]、a[2]单独放在sizeof内部或者&数组名,就表示整个数组

(5)没有像(4)那种,a、a[0]、a[1]、a[2]就表示首元素的地址

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kubernetes·陈述式声明式资源管理

目录 k8s陈述资源管理方法的说明 陈述式资源管理方法 声明式资源管理方法 GUI式资源管理方法 kubectl命令行工具 的说明 查看版本信息 查看资源对象简写 查看集群信息 配置kubectl自动补全 node节点查看日志 k8s基本信息查看 查看 master 节点状态 查看命名空间 …

【MySQL】MySQL的安装与配置环境变量(使其在控制台上使用)

作者主页&#xff1a;paper jie_博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《MySQL》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精力)打造&a…

sqlite3 关系型数据库语言 SQL 语言

SQL(Structured Query Language)语言是一种结构化查询语言,是一个通用的,功能强大的关系型数据库操作语言. 包含 6 个部分: 1.数据查询语言(DQL:Data Query Language) 从数据库的二维表格中查询数据,保留字 SELECT 是 DQL 中用的最多的语句 2.数据操作语言(DML) 最主要的关…

【Git企业开发】第四节.Git的分支管理策略和bug分支

文章目录 前言一、Git的分支管理策略 1.1 Fast forward 模式和--no-ff 模式 1.2 企业分支管理策略二、bug分支三、删除临时分支四、总结总结 前言 一、Git的分支管理策略 1.1 Fast forward 模式和--no-ff 模式 通常合并分支时&#xff0c;如果可能&#xff0c;Git 会…

Mac docker+vscode

mac 使用docker vs code 通过vscode 可以使用docker容器的环境。 可以在容器安装gdb, 直接调试代码。 创建容易时候可以指定目录和容易目录可以共享文件。

空气质量查询API促使空气数据可视化

引言 在当今的现代化社会中&#xff0c;关注和改善空气质量已成为人们共同的关切。随着科技的不断发展&#xff0c;空气质量查询API为我们提供了一种前所未有的方式来实时监测、分析和改善我们所处的环境。这一工具不仅让我们更深入地了解空气质量&#xff0c;还鼓励了空气数据…

Java如何使用KEPserver 实现S71500 OPC通信

一.PLC和OPC 使用的PLC&#xff1a;西门子PLC S7-1500 使用的OPC server软件&#xff1a; KEPServer V6 二.连接测试 OPC是工业控制和生产自动化领域中使用的硬件和软件的接口标准&#xff0c;以便有效地在应用和过程控制设备之间读写数据。O代表OLE(对象链接和嵌入)&am…

Qt 使用Quazip解压缩、压缩文件

1.环境搭建 Quazip&#xff0c;是在zlib基础上进行了简单封装的开源库&#xff0c;适用于多种平台&#xff0c;利用它可以很方便将单个或多个文件打包为zip文件&#xff0c;且打包后的zip文件可以通过其它工具打开。 下载Quazip QuaZIP download | SourceForge.net 解压后&…

cnpm windows系统安装后查看版本cnpm -v报错Error: Cannot find module ‘node:util‘

1、报错截图 2、原因 在网上查了一些资料&#xff0c;有的说配置环境变量就可以&#xff0c;但经过配置后发现还是会报错。又查到说是由于cnpm和npm的版本不一致导致的&#xff0c;最后尝试成功解决&#xff01;&#xff01;&#xff01; 2、解决办法 1、先卸载掉之前安装的c…

【扩散模型】理解扩散模型的微调(Fine-tuning)和引导(Guidance)

理解扩散模型的微调Fine-tuning和引导Guidance 1. 环境准备2. 加载预训练过的管线3. DDIM——更快的采样过程4. 微调5. 引导6. CLIP引导参考资料 微调&#xff08;Fine-tuning&#xff09;指的是在预先训练好的模型上进行进一步训练&#xff0c;以适应特定任务或领域的过程。这…

DSP 开发例程: 单镜像多核引导

目录 DSP 开发例程: 单镜像多核引导新建工程源码编辑multicore_boot.c config.hos.cmain.c测试 DSP 开发例程: 单镜像多核引导 此例程实现在 EVM6678L 开发板上将单镜像应用程序进行多核引导, 核0-核4 分别控制一个LED 闪烁, 并通过串口打印日志信息. 例程源码可从我的 gitee …

今日温馨早安问候语,祝大家平安健康早安吉祥

用清晨的阳光沐浴&#xff0c;给你舒展;用清新的空气洗漱&#xff0c;给你舒心;伴清莹的雨露散步&#xff0c;给你舒情;向美好的一天欢呼&#xff0c;给你舒怀&#xff0c;用快乐的词汇凝聚&#xff0c;给你祝福&#xff0c;祝你在绚丽的晨光中走好每一天。朋友&#xff0c;早安…

PyCharm社区版安装

PyCharm社区版安装 到中国官网下载 https://www.jetbrains.com/zh-cn/pycharm/download/?sectionwindows 首次创建项目&#xff0c;会自动下载安装Python 3.9 社区版的区别 社区版的区别

HTTP和HTTPS本质区别——SSL证书

HTTP和HTTPS是两种广泛使用的协议&#xff0c;尽管它们看起来很相似&#xff0c;但是它们在网站数据传输的安全性上有着本质上的区别。 HTTP是明文传输协议&#xff0c;意味着通过HTTP发送的数据是未经加密的&#xff0c;容易受到拦截、窃听和篡改的风险。而HTTPS通过使用SSL或…

vue 获取上一周和获取下一周的日期时间

效果图&#xff1a; 代码 <template><div><div style"padding: 20px 0;"><div style"margin-left: 10px; border-left: 5px solid #0079fe; font-size: 22px; font-weight: 600; padding-left: 10px">工作计划</div><di…

使用 Docker 部署高可用 MongoDB 分片集群

使用 Docker 部署 MongoDB 集群 Mongodb 集群搭建 mongodb 集群搭建的方式有三种&#xff1a; 主从备份&#xff08;Master - Slave&#xff09;模式&#xff0c;或者叫主从复制模式。副本集&#xff08;Replica Set&#xff09;模式。分片&#xff08;Sharding&#xff09;…

网络协议--TCP的超时与重传

21.1 引言 TCP提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确认都有可能会丢失。TCP通过在发送时设置一个定时器来解决这种问题。如果当定时器溢出时还没有收到确认&#xff0c;它就重传该数据。对任何实现而言&#xff0c;关键之处就在于超时和重…

Mac 上安装 Emscripten

背景&#xff1a;Web 端需要使用已有的 C 库&#xff0c;需要将 C 项目编译成 WebAssembly(.wasm) 供 js 调用。 Emscripten 可以将 C 编译成 .wasm 一、下载源码 # 下载 emsdk 源码 git clone https://github.com/emscripten-core/emsdk.git# 下载完成后进入到 emsdk 项目根…

2021-arxiv-LoRA Low-Rank Adaptation of Large Language Models

2021-arxiv-LoRA Low-Rank Adaptation of Large Language Models Paper: https://arxiv.org/abs/2106.09685 Code: https://github.com/microsoft/LoRA 大型语言模型的LoRA低秩自适应 自然语言处理的一个重要范式包括对通用领域数据的大规模预训练和对特定任务或领域的适应。…

不容错过的2023年度线框图工具Top 8

线框图工具可以快速呈现设计师的灵感。在任何项目的开始阶段&#xff0c;选择一个方便的线框图工具都是最好的选择。如今&#xff0c;线框图工具的出现并不夸张。各种工具都很容易获得&#xff0c;但选择太多确实很容易给设计师的选择带来困难。 买东西都讲性价比&#xff0c;…