【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

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

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

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

相关文章

【深入理解DETR】DETR的原理与算法实现

1 DETR算法概述 ①端到端 ②Transformer-model 之前的方法都需要进行NMS操作去掉冗余的bounding box或者手工设计anchor&#xff0c; 这就需要了解先验知识&#xff0c;增加从超参数anchor的数量&#xff0c; 1.1 训练测试框架 一次从图像中预测n个object的类别 训练阶段我们…

【PyQt】12-滑块、计数控件

文章目录 前言一、滑块控件 QSlider运行结果 二、计数器控件 QSpinBox运行结果 总结 前言 1、滑块控件 2、计数控件 一、滑块控件 QSlider #Author &#xff1a;susocool #Creattime:2024/2/15 #FileName:28-滑块控件 #Description: 通过滑块选择字体大小 import sys from PyQ…

基于 Python 深度学习的电影评论情感分析系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Linux实用指令

Linux实用指令 1.指定运行级别 运行级别说明&#xff1a; 0 &#xff1a;关机 1 &#xff1a;单用户【找回丢失密码】 2&#xff1a;多用户状态没有网络服务 3&#xff1a;多用户状态有网络服务 4&#xff1a;系统未使用保留给用户 5&#xff1a;图形界面 6&#xff1a;系统重…

海量数据处理商用短链接生成器平台 - 3

第三章 商用短链平台实战-账号微服务流量包设计 第1集 账号微服务和流量包数据库表索引规范讲解 简介&#xff1a;账号微服务和流量包数据库表索引规范讲解 索引规范 主键索引名为 pk_字段名; pk即 primary key;唯一索引名为 uk_字段名&#xff1b;uk 即 unique key普通索引…

【C++航海王:追寻罗杰的编程之路】关于模板,你知道哪些?

目录 1 -> 泛型编程 2 -> 函数模板 2.1 -> 函数模板概念 2.2 -> 函数模板格式 2.3 -> 函数模板的原理 2.4 -> 函数模板的实例化 2.5 -> 函数参数的匹配原则 3 -> 类模板 3.1 -> 类模板的定义格式 3.2 -> 类模板的实例化 1 -> 泛型编…

C++:继承与派生基础

引入&#xff1a; 由自然界的动物繁衍的规律&#xff08;eg: 动物继承父类的一切属性&#xff0c;由父类派生并增加自己的新特征&#xff09;我们引入C语言在类的使用中描述此类问题。 为解决代码重复使用、提升效率&#xff0c;引入继承机制&#xff1a;允许保留原有类的特性…

Git快速掌握,通俗易懂

Git分布式版本控制工具 介绍 Git是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或小或大的项目。Git是由Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件。Git可以帮助开发者们管理代码的版本&#xff0c;避免代码冲突&#…

ESP32学习(2)——点亮LED灯

1.前期准备 开发板原理图如下&#xff1a; 可见LED灯接在了GPIO2口 那么要如何编写代码控制GPIO口的电平高低呢&#xff1f; 我们可以参考micropython的官方文档Quick reference for the ESP32 — MicroPython latest documentation 可见&#xff0c;需要导入machine包 若要…

【教程】C++语言基础学习笔记(九)——指针

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【C语言基础学习】系列文章 第一章 《项目与程序结构》 第二章 《数据类型》 第三章 《运算符》 第四章 《流程控制》 第五章…

面向智算服务,构建可观测体系最佳实践

作者&#xff1a;蓟北 构建面向 AI、大数据、容器的可观测体系 &#xff08;一&#xff09;智算服务可观测概况 对于越来越火爆的人工智能领域来说&#xff0c;MLOps 是解决这一领域的系统工程&#xff0c;它结合了所有与机器学习相关的任务和流程&#xff0c;从数据管理、建…

【C语言】内存函数memcpy和memmove的功能与模拟实现

1.memcpy 功能&#xff1a;把source指向的前num个字节内容拷贝到destination指向的位置去&#xff0c;可以拷贝任意类型的数据。 注&#xff1a;1.memcpy并不关心\0&#xff0c;毕竟传的也不一定是字符串&#xff0c;因此拷贝过程中遇到\0也不会停下来。 2.num的单位是字节&a…

基于Echarts的可视化项目

整体的效果 概览区域 <!-- 概览区域模块制作 --><div class"panel overview"><div class"inner"><ul><li><h4>2190</h4><span><i class"icon-dot"></i>设备总数</span></…

Java 基于springboot+vue在线外卖点餐系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

深度学习的新进展:探索人工智能的未来

文章目录 &#x1f4d1;引言深度学习技术概述计算机视觉领域的深度应用自然语言处理的深度革命跨领域应用的深度拓展深度学习的挑战与未来展望结语 &#x1f4d1;引言 在科技日新月异的今天&#xff0c;深度学习作为人工智能领域的一颗璀璨明珠&#xff0c;正在引领着技术创新…

ElasticSearch分词器和相关性详解

目录 ES分词器详解 基本概念 分词发生时期 分词器的组成 切词器&#xff1a;Tokenizer 词项过滤器&#xff1a;Token Filter 停用词 同义词 字符过滤器&#xff1a;Character Filter HTML 标签过滤器&#xff1a;HTML Strip Character Filter 字符映射过滤器&#x…

linux系统zabbix监控配置电话告警

电话报警 睿象云官网操作zabbix-server主机操作睿象云操作zabbix-server的web页面操作 睿象云官网&#xff1a;https://www.aiops.com/ 睿象云官网操作 登录睿象云平台后点击智能告警平台 在集成栏选择监控工具选择zabbix 填写应用名称保存并获取key zabbix-server主机操…

php基础学习之文件包含

描述 在一个php脚本中&#xff0c;将另一个php文件包含进来&#xff0c;合作实现某种功能 这个描述看起来似乎和C/Java等语言的头文件/包有点类似&#xff0c;但本质是不一样的 打个比方&#xff1a; C/Java的头文件/包更像是一个工具箱&#xff0c;存放各种很完善的工具&#…

找不到目标和方向,怎么办?

现代社会里&#xff0c;许多人常见的症状&#xff0c;就是「空心病」。 什么是空心病呢&#xff1f;类似这样&#xff1a; 我知道要有目标&#xff0c;但我就是不知道想做什么&#xff0c;感觉对一切事物都提不起兴趣&#xff0c;没有动力&#xff0c;怎么办&#xff1f; 这个…

骑士遍历初级版

时间限制&#xff1a;1秒 内存限制&#xff1a;128M 题目描述 如图&#xff0c;从左下角A点出发&#xff0c;马只能向右走&#xff0c;根据马走日字的规则&#xff0c;究竟如何走才能到达右上角B点 输入描述 两个整数x、y&#xff0c;代表右上角B点的坐标&#xff0c…