浅学指针(5)sizeof和strlen的进阶理解

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 1. sizeof和strlen的对⽐
    • 1.1 sizeof
    • sizeof不是函数,是运算符
  • 1.2 strlen
    • 1.3 sizeof 和 strlen的对⽐
  • 2. 数组和指针笔试题解析
    • • sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节 • &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素 的地址是有区别的) 除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
    • 2.1 ⼀维数组
    • 2.2 字符数组
    • 代码4: 这里有重要内容
    • strlen计算内容是地址时,计算的是地址的内容
  • 2.3 ⼆维数组
  • 3. 指针运算笔试题解析
    • 3.2 题⽬2
    • #的作用打印Ox前缀
    • 3.3 题⽬3
    • 3.4 题⽬4
    • 3.5 题⽬5
    • 做这种题最好画图
    • 3.6 题⽬6
    • 3.7 题⽬7


前言

目的:深入学习sizeof和strlen和有关2维数组的指针形式

1. sizeof和strlen的对⽐

1.1 sizeof

在学习操作符的时候,我们学习了 sizeof , sizeof 计算变量所占内存内存空间⼤⼩的,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。
⽐如:

sizeof不是函数,是运算符

#inculde <stdio.h>
int main()
{int a = 10;printf("%d\n", sizeof(a));printf("%d\n", sizeof a);//也可以这样printf("%d\n", sizeof(int));return 0;
}

输出结果都是一样的,都是4,

1.2 strlen

strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:

	size_t strlen ( const char * str );

统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找。

#include <stdio.h>
int main()
{char arr1[3] = {'a', 'b', 'c'};char arr2[] = "abc";printf("%d\n", strlen(arr1));//1printf("%d\n", strlen(arr2));//2printf("%d\n", sizeof(arr1));//3printf("%d\n", sizeof(arr1));//4return 0;
}

代码1:随机值,没有\0; 代码2:结果是3
代码3:结果3 代码4:结果是4

1.3 sizeof 和 strlen的对⽐

(1)sizeof

  1. sizeof是操作符。
  2. sizeof计算操作数所占内存的⼤⼩,单位是字节。
  3. 不关注内存中存放什么数据。
    (2)strlen
    strlen
  4. strlen是库函数,使⽤需要包含头⽂件 string.h。
  5. srtlen是求字符串⻓度的,统计的是 \0 之前字符的隔个数。
  6. 关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能会越界。

2. 数组和指针笔试题解析

后面所有题都是在下面基础上:

• sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,
单位是字节
• &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素
的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。

2.1 ⼀维数组

写出所占字节数

	int a[] = {1,2,3,4};printf("%d\n",sizeof(a));//单单数组名,是整个数组,16printf("%d\n",sizeof(a+0));//首元素地址加0,为地址4/8个字节printf("%d\n",sizeof(*a));//为首元素内容,4printf("%d\n",sizeof(a+1));//首元素地址加1,为第2个元素地址 ,4/8printf("%d\n",sizeof(a[1]));//4printf("%d\n",sizeof(&a));//地址 4/8printf("%d\n",sizeof(*&a));//所有元素地址,解引用为所有元素内容,4*4=16printf("%d\n",sizeof(&a+1));//地址,4/8printf("%d\n",sizeof(&a[0]));//地址4/8printf("%d\n",sizeof(&a[0]+1));//首元素地址加1,第2个元素地址,4/8

2.2 字符数组

代码1:

	char arr[] = {'a','b','c','d','e','f'};printf("%d\n", sizeof(arr));//计算的是整个数组大小,6个字节printf("%d\n", sizeof(arr+0));//arr+0是数组第一个元素的地址4/8printf("%d\n", sizeof(*arr));//*arr是首元素,1printf("%d\n", sizeof(arr[1]));//1printf("%d\n", sizeof(&arr));//整个数组地址,还是地址4/8printf("%d\n", sizeof(&arr+1));//4/8printf("%d\n", sizeof(&arr[0]+1));//4/8

代码2:

char arr[] = {'a','b','c','d','e','f'};printf("%d\n", strlen(arr));//随机值,因为没有\0printf("%d\n", strlen(arr+0));//随机值printf("%d\n", strlen(*arr));//err(错误)'b'没有\0printf("%d\n", strlen(arr[1]));//errprintf("%d\n", strlen(&arr));//随机值printf("%d\n", strlen(&arr+1));//随机值printf("%d\n", strlen(&arr[0]+1));//随机值

代码3:

	char arr[] = "abcdef";printf("%d\n", sizeof(arr));//7printf("%d\n", sizeof(arr+0));//arr+0是数组首元素的地址,地址的大小4/8printf("%d\n", sizeof(*arr));//*arr是数组首元素地址,1printf("%d\n", sizeof(arr[1]));//1printf("%d\n", sizeof(&arr));//整个数组地址,数组地址也是地址4/8printf("%d\n", sizeof(&arr+1));//&arr+1跳过整个数组,指向了数组的后,4/8printf("%d\n", sizeof(&arr[0]+1));//&arr[0]+1是第2个元素地址4/8

代码4:
这里有重要内容

	char arr[] = "abcdef";printf("%d\n", strlen(arr));//6printf("%d\n", strlen(arr+0));//arr+0是首元素地址,6printf("%d\n", strlen(*arr));//err(错误)printf("%d\n", strlen(arr[1]));//err'b'没有\0printf("%d\n", strlen(&arr));//————&arr虽然是数组地址,但是也是指向数组起始位置printf("%d\n", strlen(&arr+1));//随机值printf("%d\n", strlen(&arr[0]+1));//&arr+1是第2个元素的地址

strlen计算内容是地址时,计算的是地址的内容

代码5:

	char *p = "abcdef";printf("%d\n", sizeof(p));//p是指针变量,是地址4/8printf("%d\n", sizeof(p+1));//p+1是'b' 的地址,4/8printf("%d\n", sizeof(*p));//*p计算'a'大小1个字节printf("%d\n", sizeof(p[0]));//p[0] = *(p+0) 1个字节printf("%d\n", sizeof(&p));//&p是地址,这里相当于2级指针4/8printf("%d\n", sizeof(&p+1));//&p+1是指向p指针变量后面的空间,也是地址,是4/8字节printf("%d\n", sizeof(&p[0]+1));//&p[0]+1是'b'的地址,是地址就是4/8个字节

代码6:

	char *p = "abcdef";printf("%d\n", strlen(p));//6printf("%d\n", strlen(p+1));//跳过1个字节,计算后面的为5printf("%d\n", strlen(*p));//errprintf("%d\n", strlen(p[0]));//err一个字节printf("%d\n", strlen(&p));//随机值printf("%d\n", strlen(&p+1));//随机值printf("%d\n", strlen(&p[0]+1));//5

2.3 ⼆维数组

	int a[3][4] = {0};printf("%d\n",sizeof(a));//4*12=48printf("%d\n",sizeof(a[0][0]));//4printf("%d\n",sizeof(a[0]));//a[0]是第一行这个一维数组的数组名,数组名单独放在sizeof了,计算的是第一行大小,单位是字节,16printf("%d\n",sizeof(a[0]+1));//a[]第一行这个一维数组的数组名,这里表示数组首元素,也就是a[0][0]的地址,a[0] + 1是a[0][1]的地址printf("%d\n",sizeof(*(a[0]+1));//a[0][1] - 4个字节printf("%d\n",sizeof(a+1));//a是二维数组的数组名,但是没有&,也没有单独放在sizeof内部,所以这里的a是数组收元素的地址,应该是第一行的地址,a+1是第二行的地址printf("%d\n",sizeof(*(a+1)));//*(a + 1) ==> a[1] - 第二行的数组名,单独放在sizeof内部,计算的是第二行的大小,为16printf("%d\n",sizeof(&a[0]+1));//&a[0]是第一行的地址,&a[0]+1就是第二行的地址,4/8printf("%d\n",sizeof(*(&a[0]+1)));//访问的是第二行,计算的是第二行的大小,16个字节,相当于放在int(*p)[4] = &a[o] + 1;printf("%d\n",sizeof(*a));//这里的a是第一行的地址,*a就是第一行,sizeof(*a)计算的是第一行的大小-16printf("%d\n",sizeof(a[3]));//这里不存在越界,因为sizeof内部的表达式不会真实计算的,计算的是第四行的类型大小-16

数组名的意义:

  1. sizeof(数组名),这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩。
  2. &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址。
  3. 除此之外所有的数组名都表⽰⾸元素的地址。

3. 指针运算笔试题解析

3.1 题⽬1:

#include <stdio.h>
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int *ptr = (int *)(&a + 1);printf( "%d,%d", *(a + 1), *(ptr - 1));return 0;
}
//程序的结果是什么?

在这里插入图片描述
*(ptr-1)解析:
在这里插入图片描述

3.2 题⽬2

指针+整数

//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥?
struct Test
{int Num;char *pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{printf("%p\n", p + 0x1);//0x100000+20 == x100014printf("%p\n", (unsigned long)p + 0x1);//0x100000+1 == 0x100001printf("%p\n", (unsigned int*)p + 0x1);//0x100000+1 == 0x100004return 0;
}

结果:
在这里插入图片描述
也可以以16进制打印:

struct Test
{int Num;char *pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{printf("%#x\n", p + 0x1);//0x100000+20 == x100014printf("%#x\n", (unsigned long)p + 0x1);//0x100000+1 == 0x100001printf("%#x\n", (unsigned int*)p + 0x1);//0x100000+1 == 0x100004return 0;
}

#的作用打印Ox前缀

结果:
在这里插入图片描述

3.3 题⽬3

重点看

#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };//这里是(),是逗号表达式,不是{},逗号表达式结果是运算到最右边的结果//int a[3][2] = { 1, 3, 5 };int *p;p = a[0];printf( "%d", p[0]);return 0;
}

分析:
在这里插入图片描述
输出结果:
在这里插入图片描述
为什么是1,其实是把a[0](数组第一行)给p,其实给的是第一行首元素地址。

3.4 题⽬4

//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{int a[5][5];int(*p)[4];p = a;printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//-4,-4(元素个数)return 0;
}

分析:
在这里插入图片描述
在这里插入图片描述
输出结果:
在这里插入图片描述

3.5 题⽬5

#include <stdio.h>
int main()
{int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int *ptr1 = (int *)(&aa + 1);//跳过一个数组int *ptr2 = (int *)(*(aa + 1));//相当于a[1],第2行,ptr得到的是第2行首元素地址printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));return 0;
}

做这种题最好画图

在这里插入图片描述

输出结果:
在这里插入图片描述

3.6 题⽬6

#include <stdio.h>
int main()
{char *a[] = {"work","at","alibaba"};//指针数组char**pa = a;pa++;printf("%s\n", *pa);return 0;
}

分析:

在这里插入图片描述

输出结果:
在这里插入图片描述

3.7 题⽬7

#include <stdio.h>
int main()
{char *c[] = {"ENTER","NEW","POINT","FIRST"};char**cp[] = {c+3,c+2,c+1,c};char***cpp = cp;printf("%s\n", **++cpp);printf("%s\n", *--*++cpp+3);printf("%s\n", *cpp[-2]+3);printf("%s\n", cpp[-1][-1]+1);return 0;
}

分析:
解引用cpp是找到cp[ ]里面的内容如:c + 3
在这里插入图片描述
在这里插入图片描述
输出结果:
在这里插入图片描述
好了,指针的学习就到这里就结束了,都看到这里了,点一个赞,谢谢。

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

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

相关文章

51单片机应用从零开始(九)·数组

目录 1. 用字符型数组控制 P0 口 8 位 LED 流水点亮 2. 用 P0 口显示字符串常量 1. 用字符型数组控制 P0 口 8 位 LED 流水点亮 C语言中的字符型数组是一种数据类型&#xff0c;它是一个由字符组成的序列&#xff0c;以空字符\0结尾。在声明字符型数组时&#xff0c;需要指…

Git【成神路】

目录 1.为啥要学git啊&#xff1f;&#x1f615;&#x1f615;&#x1f615; 2.版本控制软件的基本功能 &#x1f91e;&#x1f91e;&#x1f91e; 3.集中式版本控制 &#x1f936;&#x1f936;&#x1f936; 4.分布式版本控制&#x1f60e;&#x1f60e;&#x1f60e; …

一款自动帮你生成UI界面和代码的AI神器

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版&#xff0c;欢迎购买。点击进入详情 只要描述你想要的UI是什么样的&#xff0c;它就能帮你生成&#xff0c;是不是很神奇&#xff1f; v0使用 AI 模型根据简单的文本提示生成用户界面和代码&#xff…

Android 13.0 SystemUI电池电量为0时延迟关机的解决方案

1.简述 在13.0系统rom定制化开发中,在系统开发中可能会遇到了在电池电量为0时这时未出现立即关机的情况,产生延时关机的问题,下面就来分析这个问题所产生的原因,然后解决这个问题 2.SystemUI电池电量为0延迟关机的核心代码 /frameworks/base/services/core/java/com/andr…

含光伏发电的变电站供电系统设计

摘要 面对全球日趋严重的能源危机问题&#xff0c;可再生能源的开发和利用得到了人们的高度重视。其中辐射到地球太阳能资源是十分富饶的&#xff0c;绿色清洁的太阳能不会危害我们的生存环境&#xff0c;因而受到了人们的广泛利用。光伏发电作为可再生能源被广泛的应用&#…

关于在PyTorch中使用cudnn.benchmark= True

关于在PyTorch中使用cudnn.benchmark True 在PyTorch中&#xff0c;cudnn.benchmark True是一个参数&#xff0c;用于启用或禁用cuDNN的基准测试模式。cuDNN是一个由NVIDIA开发的深度神经网络库&#xff0c;它为GPU提供了一个优化的计算接口。 基准测试模式是cuDNN的一个特性…

informer辅助笔记:utils/timefeatures.py

定义了一套与时间特征相关的类和函数&#xff0c;旨在从时间序列数据中提取有用的时间特征&#xff0c;以支持各种时间序列分析和预测任务 from typing import Listimport numpy as np import pandas as pd from pandas.tseries import offsets from pandas.tseries.frequenc…

2023.12.3 分布式SQL查询引擎-Presto

目录 1.Prosto简介 Apache Hadoop-MapReduce Apache Hive 2.Presto的优缺点 3.个人自用启动服务 个人自用启动服务 4.presto和hive的区别 5.presto优化 1.Prosto简介 Apache Hadoop-MapReduce 优点&#xff1a;统一、通用、简单的编程模型&#xff0c;分而治之思想处理…

利用STM32内置温度传感器实现温度监测系统

STM32微控制器是一款强大的嵌入式处理器&#xff0c;具有广泛的应用领域。其中&#xff0c;一些STM32微控制器内置了温度传感器&#xff0c;可以方便地实现温度监测功能。本文将详细介绍如何利用STM32内置温度传感器实现温度监测系统&#xff0c;并提供相应的示例代码。 一、硬…

【算法思考记录】力扣1423. 可获得的最大点数[Java, 滑动窗口]

Problem: 1423. 可获得的最大点数 date: “2023-12-03” 问题重述 正难则反&#xff0c;发挥逆向思维&#xff0c;因为最终无法选择的点数是一个连续区间&#xff0c;所以问题可转换成&#xff1a;在一个给定的数组中&#xff0c;我们需要找到移除长度为 n-k 的子数组后&#…

智慧灯杆系统平台架构设计需要考虑的几个要点

智慧灯杆是一种集成了各种先进技术的道路照明设施。它不仅提供照明服务&#xff0c;还可以具有物联网技术、视频监控、环境监测、广播通讯、无线网络覆盖等多种功能。这些智能功能可以通过互联网进行控制和管理&#xff0c;从而实现智慧城市的建设。智慧灯杆能够提升城市的智能…

Wpf 使用 Prism 实战开发Day07

待办事项页面设计 效果图: 一.布局设计 页面主要分上下布局&#xff0c;分2行进行设计&#xff0c;使用 Grid.RowDefinitions 将页面分上下2行 例如&#xff1a; <Grid.RowDefinitions><RowDefinition Height"auto"/><RowDefinition/> </Gri…

React基本知识点整理

React中引入样式的2种方式 1,内联样式 import React, { Component } from react export default class index extends Component {render() {return (<div><div style{{color:"red",fontSize:"18px"}}>内联样式</div></div>)} }…

Promise自定义封装

目录 Promise构造函数 then方法封装 catch方法封装 resolve方法封装 reject方法封装 all方法封装 race方法封装 这篇文章主要是介绍如何自己封装Promise构造函数以及其相应的方法。Promise是JS中的重点&#xff0c;很多的面试都会问到。因此需要对其有比较深入地认识。看…

创意项目开源,文生图、排序/优选等...,持续开源更新!!

热烈欢迎大家在git上star&#xff01;&#xff01;&#xff01;冲鸭&#xff01;&#xff01;&#xff01; 1.dalle1在厨房家具中文场景上训练。 GitHub - leeguandong/DALLE1: dalle1在中文家具场景的微调&#xff0c;效果并不好dalle1在中文家具场景的微调&#xff0c;效果…

【JavaSE】异常(学习笔记)

一、异常概述 异常&#xff1a;程序出错了 1、异常的分类 编译时异常&#xff1a;受检异常运行时异常&#xff1a;非受检异常 2、异常体系&#xff1a;Throwable Error&#xff1a;严重问题&#xff0c;不需要处理Exception&#xff1a;异常类&#xff0c;程序本身可以处理…

MYSQL报错 [ERROR] InnoDB: Unable to create temporary file; errno: 0

起因 服务器的mysql不支持远程访问&#xff0c;在修改完相关配置后重启服务出错。 2023-12-03T10:12:23.895459Z 0 [Note] C:\Program Files\MySQL\MySQL Server 5.7\bin\mysqld.exe (mysqld 5.7.22-log) starting as process 15684 ... 2023-12-03T10:12:23.908886Z 0 [Note…

Google Guava 事件总线工具使用详解

文章目录 事件总线特点使用 事件总线 Guava 事件总线&#xff08;EventBus&#xff09;是 Google Guava 库中的一个组件&#xff0c;用于实现发布-订阅模式的事件通信。它提供了一种简单而强大的方式&#xff0c;让不同的组件之间能够解耦、相互通信、完成事件处理。 特点 注…

C语言--每日选择题--Day33

第一题 1. 在以下给出的表达式中&#xff0c;与do-while(E)语句中的(E)不等价的表达式是&#xff08; &#xff09; A&#xff1a;(!E 0) B&#xff1a;(E > 0 || E < 0) C&#xff1a;(E 0) D&#xff1a;(E ! 0) 答案及解析 C 首先要知道(E)这个条件成立无非两种&…

nodejs基于vue的社区物业缴费报修管理系统7vwc6

运行软件:vscode 前端nodejsvueElementUi 语言 node.js 框架&#xff1a;Express/koa 前端:Vue.js 数据库&#xff1a;mysql 开发软件&#xff1a;VScode/webstorm/hbuiderx均可 数据库用MySQL,后台用vue框架 基本要求&#xff1a; 1. 对项目进行详细实际的需求分析。 2. 在网…