【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表格总结

sizeofstrlen
性质操作符是库函数,使用需要包括头文件#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

 感谢各位同伴的支持,本期指针练习篇(上)就讲解到这啦,还有指针练习篇(下),如果你觉得写的不错的话,可以给个赞,若有不足,欢迎各位在评论区讨论。   

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

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

相关文章

iTop-4412 裸机程序(二十二)- RTC时钟

目录 0.源码1. RTC2. iTop4412 中的 RTC使用的相关寄存器3. BCD编码4. 关键源码 0.源码 GitHub&#xff1a;https://github.com/Kilento/4412NoOS 1. RTC RTC是实时时钟&#xff08;Real Time Clock&#xff09;的缩写&#xff0c;是一种用于计算机系统的硬件设备&#xff0…

Matplotlib自定义辅助函数 (一):让你的图表大放异彩!

Matplotlib美化秘诀&#xff1a;自定义辅助函数&#xff0c;让你的图表大放异彩&#xff01; 利用Matplotlib进行数据可视化示例 &#x1f335;文章目录&#x1f335; &#x1f333;一、创建自定义样式函数&#x1f333;&#x1f333;二、创建自定义颜色映射&#x1f333;&…

Momentum2

攻击机 192.168.223.128 目标机 192.168.223.147 主机发现 nmap -sP 192.168.223.0/24 端口扫描 nmap -sV -A -p- 192.168.223.147 开启了22 80 端口 看一下web界面 源码&#xff0c;robots.txt ,url都观察了一下好像没什么有用信息 扫一下目录 gobuster dir -u http:…

实现JNDI

实现JNDI 问题陈述 Smart Software Developer Ltd.想要开发一款Web应用程序,它使用servlt基于雇员ID显示雇员信息,雇员ID由用户通过HTML用户界面传递。雇员详细信息存储在Employee_Master表中。另外,Web应用程序应显示网站被访问的次数。 解决方案 要解决上述问题,需要执…

Linux中sigaction函数和SIGCHLD信号的使用

sigaction函数&#xff1a; 函数说明&#xff1a;注册一个信号处理函数 函数原型&#xff1a;int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 函数参数&#xff1a; signum:捕捉的信号act:传入参数&#xff0c;…

Verilog不支持浮点数以及错误事例

Verilog 是一种硬件描述语言&#xff08;HDL&#xff09;&#xff0c;用于描述和设计数字电路和系统。它的主要目的是描述硬件行为和结构&#xff0c;因此不直接支持浮点数。Verilog 主要用于设计数字逻辑电路、处理器和其他数字系统&#xff0c;它的数据类型主要是位向量和整数…

C++ 特殊类的实现

一、请设计一个类&#xff0c;不能被拷贝 拷贝只会放生在两个场景中&#xff1a;拷贝构造函数以及赋值运算符重载&#xff0c;因此想要让一个类禁止拷贝&#xff0c;只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。 在C98中&#xff1a;将拷贝构造函数与赋值运算符重载…

【嵌入式移植】6、U-Boot源码分析3—make

U-Boot源码分析3—make all 从【嵌入式移植】4、U-Boot源码分析1—Makefile文章中可知执行make命令的时候&#xff0c;没有指定目标则使用默认目标PHONY&#xff0c;PHONY依赖项为_all all scripts_basic outputmakefile scripts dtbs。 all Makefile中第129行指定默认目标PH…

十大免费 Word 转 PDF 转换器工具榜单

将 Word 转换为 PDF 格式可以帮助您在不同操作系统之间轻松共享文件。无论您是发送重要备忘录、为客户开具发票、以一致的格式维护客户记录等等&#xff0c;PDF 都属于最流行且安全的文件格式。当您将 Word 文档转换为 PDF 格式时&#xff0c;您的项目会自动优化且更加紧凑。可…

腾讯云4核8G服务器够用吗?能支持多少人?

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

ELAdmin 部署

后端部署 按需修改 application-prod.yml 例如验证码方式、登录状态到期时间等等。 修改完成后打好 Jar 包 执行完成后会生成最终可执行的 jar。JPA版本是 2.6&#xff0c;MyBatis 版本是 1.1。 启动命令 nohup java -jar eladmin-system-2.6.jar --spring.profiles.active…

JDBC教程+数据库连接池

JDBC 1.JDBC概述 ​ JDBC&#xff0c;全称Java数据库连接&#xff08;Java DataBase Connectivity&#xff09;&#xff0c;它是使用Java语言操作关系型数据库的一套API。 ​ JDBC本质是官方&#xff08;原SUN公司&#xff0c;现ORACLE&#xff09;定义的一套操作所有关系型数…

Flutter 网络请求之Dio库

Flutter 网络请求之Dio库 前言正文一、配置项目二、网络请求三、封装① 单例模式② 网络拦截器③ 返回值封装④ 封装请求 四、结合GetX使用五、源码 前言 最近再写Flutter系列文章&#xff0c;在了解过状态管理之后&#xff0c;我们再来学习一下网络请求。 正文 网络请求对于一…

starknet之 class_hash

文章目录 问题背景什么是Class Hash问题背景 部署合约报错:ReferenceError: Buffer is not defined 什么是Class Hash 官方: https://book.starknet.io/ch04-03-01-deploy-standard-account.html?highlight=class%20hash#finding-the-class-hash 要部署智能合约,您需要在…

微软在其Windows系统中暗示了AI的未来,推出了更聪明的Copilot功能

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

批量梯度下降、随机梯度下降、小批量梯度下降

一、批量梯度下降&#xff08;Batch Gradient Descent,BGD&#xff09; 在批量梯度下降中&#xff0c;每次迭代都使用整个训练集的数据进行梯度计算和参数更新。也就是说&#xff0c;每次迭代都对所有的样本求取梯度&#xff0c;然后更新参数。由于要处理整个训练集&#xff0c…

刷题计划_冲绿名

现在 rating 是 1104 准备刷 100道 1200的题&#xff0c;把实力提升到 1200 &#xff0c;上一个绿名 每一个分数段的题都写一百道&#xff0c;争取早日上蓝 现在 虽然 cf 里面显示写了一些这个分数段的题&#xff0c;但是自己训练的时候&#xff0c;其实是没有训练一道这个分…

【Py/Java/C++三种语言详解】LeetCode每日一题240214【二叉树BFS】LeetCode102、二叉树的层序遍历

有LeetCode交流群/华为OD考试扣扣交流群可加&#xff1a;948025485 可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题 绿色聊天软件戳 od1336了解算法冲刺训练 文章目录 题目链接题目描述解题思路DFS和BFS异同用队列维护的BFS 代码PythonJavaC时空复杂度 相关习题华为OD算法/大…

Linux 基础/子目录分配/文件路径

在Linux系统中&#xff0c;整个系统只具有一个根目录“/”&#xff0c;用斜杠表示。根目录是整个文件系统的顶层目录&#xff0c;在他下面可以创建其他的目录和文件。 Linux中的子目录分配&#xff1a; /bin - 基本命令的二进制文件&#xff0c;这些命令可供所有用户使用&am…

MySQL主从环境,主库改端口后,从库如何操作?

主库&#xff1a;mysql-111 从库&#xff1a;mysql-112 主库由3306端口修改成3307后&#xff0c; 从库执行如下命令 mysql> stop slave; mysql> change master to master_port3307; mysql> CHANGE MASTER TO MASTER_HOST192.168.10.111,MASTER_USERbeifen,MASTER_PA…