【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…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...
算法250609 高精度
加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...
简单介绍C++中 string与wstring
在C中,string和wstring是两种用于处理不同字符编码的字符串类型,分别基于char和wchar_t字符类型。以下是它们的详细说明和对比: 1. 基础定义 string 类型:std::string 字符类型:char(通常为8位)…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...