【C语言】指针练习篇(上),深入理解指针---指针和数组练习题和sizeof,strlen的对比【图文讲解,详细解答】
欢迎来CILMY23的博客喔,本期系列为【C语言】指针练习篇(上),深入理解指针---指针数组练习题和sizeof,strlen的对比【图文讲解,详细解答】,图文讲解指针和数组练习题,带大家更深刻理解指针的应用,感谢观看,支持的可以给个赞哇。
前言
作为指针系列的番外练习篇,本篇主要以数组练习题为主,本期博客将用sizeof和strlen的对比开头,并且以做题的视角带入,进行深刻理解指针练习题中不同用法区别。
目录
一、sizeof和strlen的对比
1.1sizeof操作符
1.2strlen
1.3表格总结
1.4sizeof题目
二、指针,数组笔试题
2.1一维数组
2.2 字符数组
一、sizeof和strlen的对比
1.1sizeof操作符
sizeof 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。sizeof 只关注占用内存空间的大小,不在乎内存中存放什么数据,并且在计算变量的时候,括号可以省略。额外说明size_t就是为sizeof设计的。
就比如以下代码:
#include<stdio.h>int main()
{int a = 23;printf("%d\n", sizeof(a));printf("%d\n", sizeof a);printf("%d\n", sizeof(int));return 0;
}

我们可以看到,结果都是4。
1.2strlen
strlen是C语言库函数,函数功能原型如下:
size_t strlen ( const char * str );
strlen字符串长度统计的是从形参str中这个地址开始向后,\0之前字符串中字符的个数。如果没有找到\0,那么strlen函数会在内存中⼀直向后找\0字符,直到找到\0为止,所以可能存在越界查找。
就比如下面这段代码:
#include<stdio.h>
#include<string.h>int main()
{char arr[] = "SILMY23";char arr1[] = { 'S','I','L','M','Y' };printf("%d\n", strlen(arr));printf("%d\n", strlen(arr1));return 0;
}
由于前面有\0,后面没有\0,那么第二个原本的长度应该是五,但存在越界查找,所以长度必然不为5.
结果如下:

1.3表格总结
| sizeof | strlen | |
| 性质 | 操作符 | 是库函数,使用需要包括头文件#include<string.h> |
| 功能 | 计算操作数所占内存的大小,单位是字节 | 求字符串长度 |
| 特点 | 不关注内存中存放什么数据 | 关注内存中是否有\0,如果没有\0 ,就会持续往后找,可能会越界查找 |
1.4sizeof题目
请思考以下代码,L和S的值:
#include<stdio.h>int main()
{short S = 4;int I = 2;int L = sizeof(S = I + 23);printf("%d \n", L);printf("%d \n", S);return 0;
}
结果如下:

在上述代码中,S=I+23其实是没有参与计算的,因为在sizeof中的操作数如果是一个表达式,表达式就不参与计算,所以最后的S还是4。其次,sizeof计算其实是按照操作类型来推理的,比如上述中S是short两个字节的短整型,所以L是两个字节。
二、指针,数组笔试题
2.1一维数组
如果你不理解数组名可以跳转至http://t.csdnimg.cn/6zjW4,观看第二点
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));
这是在32位环境和64位环境下的结果

2.1解析:
printf("%d\n", sizeof(a));
a单独放在sizeof后面是整个数组,计算的是整个数组的大小,所以大小为16
printf("%d\n", sizeof(a + 0));a+0,a没有单独放在sizeof里面,也没有&,所以是数组首元素地址,既然是数组首元素地址那么,a+0 == a,是地址,大小就为4/8字节。
printf("%d\n", sizeof(*a));a没有单独存放在sizeof后面,所以是数组首元素地址,解引用,*a == a[0],所以计算的是数组第一个元素的大小,即为4个字节
printf("%d\n", sizeof(a + 1));a + 1同理上面的 a+0 即为4/8字节
printf("%d\n", sizeof(a[1]));a[1] == *(a + 1),计算的是数组第二个元素的大小,即为4个字节
printf("%d\n", sizeof(&a));&a, 因为a前面有&操作符,所以这里取出的是整个数组的地址,既然为地址,那么就为4/8字节
printf("%d\n", sizeof(*&a));把整个数组的地址解引用后,sizeof计算的是整个数组的大小,即为16个字节
printf("%d\n", sizeof(&a + 1));&a + 1,计算的是跳过数组大小的地址,是地址就为4/8字节
printf("%d\n", sizeof(&a[0]));&a[0],表示取出的是数组首元素的地址,大小为4/8字节
printf("%d\n", sizeof(&a[0] + 1));&a[0] + 1表示的是数组第二个元素的地址,大小为4/8字节
2.2 字符数组
2.2.1
char arr[] = {'S','I','L','M','Y'};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));
结果如下:

2.2.1解析:
printf("%d\n", sizeof(arr));
arr单独放在sizeof后面,计算整个数组大小,所以为5个字节
printf("%d\n", sizeof(arr + 0));arr+0表示是数组首元素地址,是地址就为4/8字节
printf("%d\n", sizeof(*arr));*arr将数组首元素地址解引用,sizeof计算首元素的大小,大小为1字节
printf("%d\n", sizeof(arr[1]));arr[1]表示数组第二个元素,sizeof计算第二个元素大小,大小为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字节
2.2.2
char arr[] = { 'S','I','L','M','Y' };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));
32位结果如下:

64位结果如下:

2.2.2解析
printf("%d\n", strlen(arr));
arr表示数组首元素地址,因为数组中没有明确给出字符\0,所以会导致strlen在内存中不断寻找,直到找到第一个\0 为止,因此是随机值
printf("%d\n", strlen(arr + 0));arr+0也表示数组首元素地址,因为没有\0,所以和第一种情况一样,也是随机值
printf("%d\n", strlen(*arr));
*arr,arr是数组首元素地址,解引用后得到是S,S对应的ASCII码值是83,strlen把八十三当成一个地址,造成非法访问,所以错误
printf("%d\n", strlen(arr[1]));arr[1]表示数组第二个元素,I对应的ASCII码值是73,同样的也是非法访问。
printf("%d\n", strlen(&arr));&arr表示取出整个数组的地址,从arr的首元素开始算起,直到找到第一个\0为止,所以是随机值
printf("%d\n", strlen(&arr + 1));&arr +1 表示跳过数组大小的地址,也就是从Y后面开始算起,同样因为没有\0,所以会是一个随机值,但它和&arr会相差五个元素,一个数组大小。
printf("%d\n", strlen(&arr[0] + 1));&arr[0] + 1 表示从数组第二个元素开始,因为没有\0,所以也会是一个随机值,但它和&arr相比,会差一个元素
2.2.3
char arr[] = "SILMY23";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));
结果如下:

2.2.3解析:
printf("%d\n", sizeof(arr));
arr单独放在sizeof后面,所以计算的是整个数组的大小,因为字符串后面自带一个'\0'字符,所以sizeof在计算大小的时候会把'\0'算进去,也就是八个字节。
printf("%d\n", sizeof(arr + 0));arr + 0 ,表示数组首元素的地址,那是地址大小就是4/8
printf("%d\n", sizeof(*arr));*arr是数组首元素地址解引用,得到的是S,sizeof单独计算一个S的大小,字节为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字节。
2.2.4
char arr[] = "SILMY23";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));
32位结果如下:

64位结果如下:

2.2.4解析
printf("%d\n", strlen(arr));
arr表示数组首元素地址,strlen计算的是到\0之前的字符,所以是7个字节
printf("%d\n", strlen(arr + 0));arr+0表示数组首元素地址,7个字节
printf("%d\n", strlen(*arr));arr表示数组首元素地址,但是解引用后访问的是S的ASCII码,地址83,非法访问
printf("%d\n", strlen(arr[1]));arr[1] 表示数组第二个元素,解引用后访问的是I的ASCII码,地址73,非法访问
printf("%d\n", strlen(&arr));&arr,表示整个数组的地址,也是指向数组起始位置的,那因为有\0,所以计算的是到\0之前的地址,所以是7个字节
printf("%d\n", strlen(&arr + 1));&arr + 1 ,表示跳过整个数组,指向数组末尾的地址,由于找不到\0,所以会在内存中寻找\0,因此是随机值
printf("%d\n", strlen(&arr[0] + 1));&arr[0] + 1,表示数组第二个元素的地址,计算后的大小为6.
2.2.5
char* p = "SILMY23";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));
32位结果如下图:

64位结果如下图:

2.2.5解析:
printf("%d\n", sizeof(p));
p是个char* 的指针变量,指向的对象数据类型是char,是指针变量,大小就为4/8字节
printf("%d\n", sizeof(p + 1));p + 1,表示字符I的地址,本身还是指针变量,大小就为4/8字节
printf("%d\n", sizeof(*p));*p,p本身存储的是S的地址,解引用后获得S,那么S对应的类型是char,所以大小为1字节
printf("%d\n", sizeof(p[0]));p[0],表示*(p+0)== *p,所以大小为1字节
printf("%d\n", sizeof(&p));&p,表示的是指针变量p的地址,所以大小为4/8字节
printf("%d\n", sizeof(&p + 1));&p +1 ,表示跳过一个指针变量的大小的地址,是地址,大小为4/8
printf("%d\n", sizeof(&p[0] + 1));&p[0] + 1,表示指向I的地址,是地址,大小为4/8
2.2.6
char* p = "SILMY23";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));
32位结果如下:

64位结果如下:

2.2.6解析:
printf("%d\n", strlen(p));
p是char* 的指针变量,指向的是S这个起始位置,末尾有\0,计算大小为7
printf("%d\n", strlen(p + 1));p + 1 指向的是I这个起始位置,末尾有\0,计算大小为6
printf("%d\n", strlen(*p));*p,p表示字符串S地址,但是解引用后访问的是S的ASCII码,地址83,非法访问
printf("%d\n", strlen(p[0]));p[0] == *(p+0) == *p, 同样是非法访问
printf("%d\n", strlen(&p));&p,表示的是p的地址,那从p的起始地址开始往后找\0,因为不确定\0在哪,所以是随机值
printf("%d\n", strlen(&p + 1));&p +1 ,表示跳过一个指针变量的大小的地址,从p的末尾开始查找,因为不确定\0在哪,所以是随机值
printf("%d\n", strlen(&p[0] + 1));&p[0] + 1,表示指向I的地址,计算的大小为6
感谢各位同伴的支持,本期指针练习篇(上)就讲解到这啦,还有指针练习篇(下),如果你觉得写的不错的话,可以给个赞,若有不足,欢迎各位在评论区讨论。
相关文章:
【C语言】指针练习篇(上),深入理解指针---指针和数组练习题和sizeof,strlen的对比【图文讲解,详细解答】
欢迎来CILMY23的博客喔,本期系列为【C语言】指针练习篇(上),深入理解指针---指针数组练习题和sizeof,strlen的对比【图文讲解,详细解答】,图文讲解指针和数组练习题,带大家更深刻理解指针的应用…...
2048游戏C++板来啦!
个人主页:PingdiGuo_guo 收录专栏:C干货专栏 大家好呀,我是PingdiGuo_guo,今天我们来学习如何用C编写一个2048小游戏。 文章目录 1.2048的规则 2.步骤实现 2.1: 初始化游戏界面 2.1.1知识点 2.1.2: 创建游戏界面 2.2: 随机…...
2000-2021年县域指标统计数据库
2000-2021年县域统计数据库 1、时间:2000-2021年 2、来源:县域统计年鉴 3、范围:2500县 5、指标: 地区名称、年份、行政区域代码、所属城市、所属省份、行政区域土地面积平方公里、乡及镇个数个、乡个数个、镇个数个、街道办…...
Hive on Spark配置
前提条件 1、安装好Hive,参考:Hive安装部署-CSDN博客 2、下载好Spark安装包,链接:https://pan.baidu.com/s/1plIBKPUAv79WJxBSbdPODw?pwd6666 3、将Spark安装包通过xftp上传到/opt/software 安装部署Spark 1、解压spark-3.3…...
计算机网络——11EMail
EMail 电子邮件(EMail) 3个主要组成部分 用户代理邮件服务器简单邮件传输协议:SMTP 用户代理 又名“邮件阅读器”撰写、编辑和阅读邮件输入和输出邮件保存在服务器上 邮件服务器 邮箱中管理和维护发送给用户的邮件输出报文队列保持待发…...
第13讲创建图文投票
创建图文投票实现 图文投票和文字投票基本一样,就是在投票选项里面,多了一个选项图片;、 <view class"option_item" v-for"(item,index) in options" :key"item.id"><view class"option_input&…...
Vulnhub靶机:DC3
一、介绍 运行环境:Virtualbox 攻击机:kali(10.0.2.15) 靶机:DC3(10.0.2.56) 目标:获取靶机root权限和flag 靶机下载地址:https://www.vulnhub.com/entry/dc-32,312…...
代码随想录算法训练营第三十一天|● 理论基础 ● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和
仅做学习笔记,详细请访问代码随想录 ● 理论基础 ● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和 ● 理论基础 有同学问了如何验证可不可以用贪心算法呢? 最好用的策略就是举反例,如果想不到反例,那么就试一试贪心吧。 …...
【光学】学习记录1-几何光学的近轴理论
课程来源:b站资源-光学-中科大-崔宏滨老师(感谢),本系列仅为自学笔记 【光学 中科大 崔宏滨老师 1080p高清修复(全集)】https://www.bilibili.com/video/BV1NG4y1C7T9?p2&vd_source7ba37b2cff2a1b783…...
【51单片机】AT24C02(江科大、爱上半导体)
一、AT24C02 1.AT24C02介绍 AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息 存储介质:E2PROM 通讯接口:12C总线 容量:256字节 2.引脚即应用电路 本开发板AT24C02原理图 12C地址全接地,即全为0 WE接地,没有写使能 SCL接P21 S…...
nohup基本使用
在Linux终端命令中经常要使用到在关闭终端界面的情况下需要后台挂起执行的进程,也就是关闭终端后台任务的进程还是会常驻,下面就简单介绍下 nohup 命令 1. nohup nohup 英文全称 no hang up(不挂起),默认情况下&#x…...
postgresql 手动清理wal日志的101个坑
新年的第一天,总结下去年遇到的关于WAL日志清理的101个坑,以及如何相对安全地进行清理。前面是关于WAL日志堆积的原因分析,清理相关可以直接看第三部分。 首先说明,手动清理wal日志是一个高风险的操作,尤其对于带主从的…...
【开源训练数据集3】Top3人脸数据集及其使用方法-计算机视觉应用
目录 什么是人脸数据集? Top 3 人脸数据集 CelebFaces Attributes (CelebA)数据集 Flickr-Faces-HQ (FFHQ) 数据集 野外标记面孔 (LFW) 使用先进的人脸数据集 CelebA 访问数据集 在 Pytorch 中使用 CelebA 在 Tensorflow 中使用 CelebA Flickr-Faces-HQ 数据集 (FFH…...
精灵图,字体图标,CSS3三角
精灵图 1.1为什么需要精灵图 一个网页中往往会应用很多小的背景图像作为修饰,当网页中的图像过多时,服务器就会频繁的接受和发送请求图片,造成服务器请求压力过大,这将大大降低页面的加载速度。 因此,为了有效地减少…...
.NET Core性能优化技巧
.NET Core作为一个跨平台的开源框架,以其高效、灵活和可扩展的特性受到了广大开发者的青睐。但在实际开发中,如何确保应用程序的性能始终是一个关键的问题。本文将介绍十大.NET Core性能优化技巧,帮助开发者提升应用程序的性能。 1. 使用异步…...
人类智能远远超越了物理与数理范畴
德国哲学家黑格尔曾这样写道,我们越是熟悉的东西,就越不清楚它。这或许意味着当我们对某个事物非常熟悉时,可能会陷入一种思维定势,导致我们无法客观地认识和理解它。这种思维定势可能来自于习惯、传统观念或者个人经验࿰…...
数据库管理-第149期 Oracle Vector DB AI-01(20240210)
数据库管理149期 2024-02-10 数据库管理-第149期 Oracle Vector DB & AI-01(20240210)1 机器学习2 向量3 向量嵌入4 向量检索5 向量数据库5 专用向量数据库的问题总结 数据库管理-第149期 Oracle Vector DB & AI-01(20240210…...
FlinkSql通用调优策略
历史文章迁移,稍后整理 使用DataGenerator 提前进行压测,了解数据的处理瓶颈、性能测试和消费能力 开启minibatch:"table.exec.mini-batch.enabled", "true" 开启LocalGlobal 两阶段聚合:"table.exec.m…...
Linux在云计算领域的重要作用
在云计算领域,Linux扮演着至关重要的角色。以下是Linux在云计算领域中的重要作用: 稳定性和安全性:Linux操作系统具有稳定性和安全性,可以有效地保护用户的数据安全。它具有各种安全功能,可以防止未经授权的访问&…...
sqlserver2012 解决日志大的问题 bat脚本
要解决SQL Server 2012中事务日志过大的问题,你可以创建一个批处理脚本(.bat)来定期备份事务日志。下面是一个示例批处理脚本,该脚本使用SQLCMD工具来执行事务日志备份: echo off set "DBNAMEYourDatabaseName&qu…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...




