指针的深入理解(六)

指针的深入理解(六)

个人主页:大白的编程日记
感谢遇见,我们一起学习进步!


文章目录

  • 指针的深入理解(六)
    • 前言
    • 一. sizeof和strlen
      • 1.1sizeof
      • 1.2strlen
      • 1.3sizeof和strlen对比
    • 二.数组名和指针加减
      • 2.1数组名的理解
      • 2.2指针加减整数
      • 2.3指针的大小
    • 三. 数组和指针笔试题解析
      • 3.1 一维数组
      • 3.2 字符数组
      • 3.3常量字符串
    • 四.二维数组
      • 4.1二维数组的理解
      • 4.2二维数组练习
    • 后言

前言

经过前面的学习我们已经把指针的内容全部学完了。所谓”纸上得来终觉浅,绝知此事要躬行“。今天小编就带着大家进行指针知识的练习,也相当与复习一遍学过的内容。我们进入正题,向着大厂进发!


一. sizeof和strlen

1.1sizeof

  1. 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;
}

1.2strlen

  1. strlen

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

 size_t strlen ( const char * str );

strlen函数是用来统计字符串个数的,统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。
strlen 函数会⼀直向后找 \0 字符,直到找到为止,所以可能存在越界查找
注意:strlen函数的使用需要包含头文件<string.h>

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

1.3sizeof和strlen对比

  • 本质:sizeof是操作符 , strlen是库函数。
  • 功能:sizeof计算空间大小,strlen统计字符个数。
  • 注意事项:sizeof不关注内存内容,只关注内存大小
    strlen通过观察内存的\0统计,遇到\0停下。若没有\0则可能产生越界现象。

二.数组名和指针加减

2.1数组名的理解

  • 数组名是数组首元素的地址。
    但有两个特殊情况
  • sizeof(数组名),此时的数组名表示整个数组, 计算的是整个数组的大小,单位是字节。
    &(数组名),此时的数组名也表示整个数组,取出的是整个数组的大小。
    注意括号里必须只有数组名!

2.2指针加减整数

  • 指针加减整数,指针向前或向后移动。
  • 指针加减移动多大距离(单位是字节),取决于指针类型
  • 举例:int类型的指针+1跳过一个整形,指向下一个整型。
    指针地址+4
    char类型的指针+1跳过一个字符,指向下一个字符。
    指针地址+1

2.3指针的大小

  • 指针大小取决于当前环境
  • 32位环境指针大小4字节
  • 64位环境指针大小8字节

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

3.1 一维数组

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));//1
printf("%d\n",sizeof(a+0));//2
printf("%d\n",sizeof(*a));//3
printf("%d\n",sizeof(a+1));//4
printf("%d\n",sizeof(a[1]));//5
printf("%d\n",sizeof(&a));//6
printf("%d\n",sizeof(*&a));//7
printf("%d\n",sizeof(&a+1));//8
printf("%d\n",sizeof(&a[0]));//9
printf("%d\n",sizeof(&a[0]+1));//10
printf("%d\n",sizeof(a));//1
//数组名单独放在sizeof里面,
//计算整个数组的大小 4*4==16
printf("%d\n",sizeof(a+0));//2
//a没有单独放在sizeof里面,
//a就是首元素地址
//指针+0跳过0的整型元素,还是指向首元素,
//地址就是指针,指针的大小是4/8
printf("%d\n",sizeof(*a));//3
//a是数组首元素地址,*a就是首元素
//int类型,4字节大小
printf("%d\n",sizeof(a+1));//4
//a首元素地址,a+1跳过一个整型,指向第二个元素
//指针加减整数还是指针,大小4/8字节
printf("%d\n",sizeof(a[1]));//5
//a[1]就是数组第二个元素,大小为4字节
printf("%d\n",sizeof(&a));//6
//&a取出数组首元素地址,数组的地址也是指针
//计算指针的大小,4/8字节
printf("%d\n",sizeof(*&a));//7
//&a取出整个数组的地址,*(数组的地址)访问呢整个数组
//计算整个数组的大小,4*4==16
printf("%d\n",sizeof(&a+1));//8
//&a是整个数组的地址,类型是数组指针,+1跳过整个数组
//指向数组后第一个字节的地址,地址是指针
//大小4/8字节
printf("%d\n",sizeof(&a[0]));//9
//a[0]数组首元素,&a[0]取出数组首元素地址
//地址就是指针,4/8字节
printf("%d\n",sizeof(&a[0]+1));//10
//a[0]数组首元素,&a[0]取出数组首元素地址
//首元素地址+1跳过一个整型,指向第二个元素
//还是指针,4/8字节

  • 验证:
  • 64位环境:
    在这里插入图片描述
  • 32位环境:

3.2 字符数组

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//1
printf("%d\n", sizeof(arr+0));//2
printf("%d\n", sizeof(*arr));//3
printf("%d\n", sizeof(arr[1]));//4
printf("%d\n", sizeof(&arr));//5
printf("%d\n", sizeof(&arr+1));//6
printf("%d\n", sizeof(&arr[0]+1));//7
printf("%d\n", sizeof(arr));//1
//arr数组名单独放在sizeof内部,计算整个数组的大小,1*6=6字节
printf("%d\n", sizeof(arr+0));//2
//arr是数组名,就是数组首元素的地址,+0跳过0的字节,指向首元素
//还是指针,4/8字节
printf("%d\n", sizeof(*arr));//3
//arr是数组首元素的地址,*arr解引用访问数组首元素,1字节
printf("%d\n", sizeof(arr[1]));//4
//arr[1]是数组第二个元素,1字节
printf("%d\n", sizeof(&arr));//5
//arr是数组名,&arr取出整个数组的地址,数组的地址也是地址
//还是指针,4/8字节
printf("%d\n", sizeof(&arr+1));//6
//&arr是整个数组的地址,+1跳过整个数组,指向数组后面的位置
//还是指针,4/8个字节
printf("%d\n", sizeof(&arr[0]+1));//7
//&arr[0]取出数组首元素的地址,+1跳过一个字节,指向第二个字符
//还是指针,4/8字节

  1. 验证:
  2. 64位环境:
  3. 32位环境:

char arr[] = {'a','b','c','d','e','f'};数组没有\0
printf("%d\n", strlen(arr));//1
//arr是数组名,数组首元素地址开始统计
//没有\0,什么时候遇到\0不知道,是随机值
printf("%d\n", strlen(arr+0));//2
//arr是数组名,是数组首元素地址,
//arr+0跳过0个字节,指向第一个元素,也是和上面一样的随机值
printf("%d\n", strlen(*arr));//3
//arr是数组名,是数组名首元素地址,*arr-'a'-ascllm码值97
//相当于把97作为地址传给strlen,strlen接收野指针,代码是错误的
printf("%d\n", strlen(arr[1]));//4
//arr[1]-'b'-98,把98传给strlen,也是野指针,也是错误的
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1))
printf("%d\n", strlen(arr));//1
//arr是数组名,数组首元素地址开始统计
//没有\0,什么时候遇到\0不知道,是随机值
printf("%d\n", strlen(arr+0));//2
//arr是数组名,是数组首元素地址,
//arr+0跳过0个字节,指向第一个元素,也是和上面一样的随机值
printf("%d\n", strlen(*arr));//3
//arr是数组名,是数组名首元素地址,*arr-'a'-ascllm码值97
//相当于把97作为地址传给strlen,strlen接收野指针,代码是错误的

printf("%d\n", strlen(arr[1]));//4
//arr[1]-'b'-98,把98传给strlen,也是野指针,也是错误的
printf("%d\n", strlen(&arr));//p1表示
//&arr取出数组的地址,数组的地址也指向数组首元素,设为x随机值
printf("%d\n", strlen(&arr+1));//p2表示
//&arr取出数组的地址,&arr+1跳过数组,指向数组后的位置,x-6的随机值
printf("%d\n", strlen(&arr[0]+1))//p3表示
//&arr[0]是数组首元素地址,&arr[0]+1跳过一个字节,指向第二个元素
//x-1的随机值

  • 验证:

3.3常量字符串

双引号里面的字符串就是常量字符串,常量字符串末尾自动补上\0.

char arr[] = "abcdef"//常量字符串,末尾自动补\0
printf("%d\n", strlen(arr));//1
printf("%d\n", strlen(arr+0));//2
printf("%d\n", strlen(*arr));//3
printf("%d\n", strlen(arr[1]));//4
printf("%d\n", strlen(&arr));//5
printf("%d\n", strlen(&arr+1));//6
printf("%d\n", strlen(&arr[0]+1));//7
printf("%d\n", strlen(arr));//1
//arr是数组名,就是数组首元素地址,统计6个字符。
printf("%d\n", strlen(arr+0));//2
//arr是数组名,就是数组首元素地址,+0跳过0个字节
//还是数组首元素地址,//统计6个字符
printf("%d\n", strlen(*arr));//3
//arr是数组名,就是数组首元素的地址,*arr就是首元素'a'
//'a'的ascll码值是97相当于把97作为地址传递给strlen,strlen得到野指针
//此时代码是有问题的

printf("%d\n", strlen(arr[1]));//4
//arr[1]就是数组第二个元素,相当于把'b'--98传给strlen,
//也是野指针,也有问题
printf("%d\n", strlen(&arr));//5
//arr是数组名,&arr是数组首元素的地址,数组首元素的地址也指向首元素
//统计的还是6个字符
printf("%d\n", strlen(&arr+1));//6
//arr是数组名,&arr是数组首元素的地址,数组首元素的地址也指向首元素
//&arr+1跳过一个数组,指向数组后面的位置,什么时候遇到\0不知道
//所以是随机值
printf("%d\n", strlen(&arr[0]+1));//7
//&arr[0]取出数组首元素的地址,+1跳过一个字节,指向第二个字符,
//从第二个字符统计,统计5个字符

四.二维数组

4.1二维数组的理解


我们可以把二维数组看一个以数组为元素的一维数组。每行数组都有一个数组名,例如二位数组第一行的数组的数组名就是a[0],
第一行的数组的数组名就是a[1],以此类推。
举个例子来验证可不可以这样理解:
例如我们访问第二行第三个元素:
我们会写成a[1][2]
a[1]就是第二行的数组名,数组名就是数组首元素的地址
首元素地址再通过【2】就跳过2个元素,访问第三个元素,
就是第二行第三个元素。说明我们的理解是没问题的。

4.2二维数组练习

int a[3][4] = {0};
printf("%d\n",sizeof(a));//1
printf("%d\n",sizeof(a[0][0]));//2
printf("%d\n",sizeof(a[0]));//3
printf("%d\n",sizeof(a[0]+1));//4
printf("%d\n",sizeof(*(a[0]+1)));//5
printf("%d\n",sizeof(a+1));//6
printf("%d\n",sizeof(*(a+1)));//7
printf("%d\n",sizeof(&a[0]+1));//8
printf("%d\n",sizeof(*(&a[0]+1)));//9
printf("%d\n",sizeof(*a));//10
printf("%d\n",sizeof(a[3]));//11
printf("%d\n",sizeof(a));//1
//数组名单独放在sizeof里,计算整个数组的大小,
//3*4*4=48
printf("%d\n",sizeof(a[0][0]));//2
//a[0][0]表示数组首元素,大小为4字节
printf("%d\n",sizeof(a[0]));//3
//第一行数组名单独放在sizeof里,计算的是第一行数组的大小
//4*4=16字节;
printf("%d\n",sizeof(a[0]+1));//4
//a[0]第一行数组的数组名,就是第一行首元素的地址,+1指向第一行第二个元素,
//还是指针,4/8个字节
printf("%d\n",sizeof(*(a[0]+1)));//5
//a[0]+1是第一行第二个元素的地址,*解引用访问第一行第二个元素,4字节
printf("%d\n",sizeof(a+1));//6
//a是二维数组的数组名,就是数组首元素的地址,就是第一行的地址
//+1跳过一行,指向第二行,还是指针,4/8字节
printf("%d\n",sizeof(*(a+1)));//7
//a+1是第二行的地址,*解引用访问第二行,计算第二行的大小
//4*4=16字节
printf("%d\n",sizeof(&a[0]+1));//8
//a[0]是第一行的数组名,&a[0]取出第一行数组的地址,
//&a[0]+1跳过一行,指向第二行,还是指针
//指针大小就是4/8
printf("%d\n",sizeof(*(&a[0]+1)));//9
//&a[0]+1第二行的地址,*解引用访问第二行的数组,计算第二行数组的大小
//4*4=16字节
printf("%d\n",sizeof(*a));//10
//a是二维数组的数组名,数组名就是数组首元素的地址,就是第一行的地址
//*解引用访问第一行,计算第一行的大小。4*4=16
printf("%d\n",sizeof(a[3]));//11
//a[3]看似越界,但是并未访问,sizeof根据类型推断。
//所以a[3]无需真实访问,根据类型推断为第四行的数组名
//数组名单独放在sizeof内部,计算第四行数组的大小,4*4=16

后言

这里就是今天跟大家分享的全部内容啦,今天的内容有点绕,但是大家直到抓紧指针加减和数组名理解这两个点,那就迎刃而解啦!今天就分享到这里,感谢小伙伴的耐心阅读。咱们下期见!拜拜~
在这里插入图片描述

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

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

相关文章

动态代理

动态代理 动态代理和静态代理角色一致。 代理类是动态生成的,不是我们直接写好的。 动态代理分为俩大类:基于接口的动态代理、基于类的动态代理 基于接口:JDK动态代理(以下示例就是这个) 基于类:cglib java字节码实现:javasist JDK动态代理 InvocationHandler Proxy …

C语言从入门到实战————编译和链接

目录 前言 1. 翻译环境和运行环境 2. 翻译环境 2.1 预处理&#xff08;预编译&#xff09; 2.2 编译 2.2.1 词法分析&#xff1a; 2.2.2 语法分析 2.2.3 语义分析 2.3 汇编 2.4 链接 3. 运行环境 前言 编译和链接是将C语言源代码转换成可执行文件的必经过程&a…

分公司=-部门--组合模式

1.1 分公司不就是一部门吗&#xff1f; "我们公司最近接了一个项目&#xff0c;是为一家在全国许多城市都有分销机构的大公司做办公管理系统&#xff0c;总部有人力资源、财务、运营等部门。" "这是很常见的OA系统&#xff0c;需求分析好的话&#xff0…

Linux 内核移植exfat驱动

简介&#xff1a; Linux系统默认可以自动识别到fat32格式的盘&#xff0c;但fat32支持的文件不能大于4G&#xff0c;所以只能将移动硬盘和U盘格式化为NTFS和exFAT这两种格式的&#xff0c;对于U盘最好格式化为exFAT。 Linux5.4以上的内核原生支持exfat格式&#xff0c;不需要你…

【LeetCode: 572. 另一棵树的子树 + 二叉树 + dfs】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

UE4_动画基础_ 使用分层动画(Using Layered Animations)

完成在移动过程中武器发射的角色制作&#xff01; 动画混合仅仅意味着在一个角色或骨架网格体上的两个或多个动画之间进行平滑过渡。在虚幻引擎4中&#xff0c;有多种方法可以应用这种混合&#xff0c;要么通过混合空间&#xff0c;或通过实际组合两个基于加权偏差或alpha值的…

开源免费的多功能PDF工具箱

它支持修改PDF、编辑PDF书签、导出PDF书签、导入书签、生成、合并、拆分、提取页面内容、提取图片、OCR 功能介绍: 修改PDF信息&#xff1a;修改文档属性、页码编号、页面链接、页面尺寸&#xff1b;删除自动打开网页等动作&#xff0c;去除复制及打印限制&#xff1b;设置阅读…

SpringBoot中这样用ObjectMapper,才够优雅!

目录 背景步骤在SpringBoot项目中要实现对象与Json字符串的互转&#xff0c;每次都需要像如下一样new 一个ObjectMapper对象&#xff1a;这样的代码到处可见&#xff0c;有问题吗&#xff1f;我们要使用jmh测试几种方式的区别&#xff1a;所以在我们真正使用的时候不要在方法中…

tesseract-ocr一站式安装与使用

目录 前言 安装tesseract-ocr 添加环境变量 1、在path中添加 2、在系統變量中添加 3、验证是否添加成功 添加语言包 更多语言包下载 示例程序 前言 如果你遇到了&#xff1a;make sure the TESSDATA_PREFIX Failed loading language \‘chi_sim 那么就是语言包缺少这个&#xf…

【简单讲解下Fine-tuning BERT】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

XAMPP本地开发环境软件的最佳替代品

在开发新网站或应用时&#xff0c;选择合适的本地开发环境是至关重要的。本地开发环境让您可以在自己的电脑上搭建和测试网站或应用&#xff0c;直到它们准备好被迁移到线上服务器。一些工具甚至提供了推送到生产环境的功能&#xff0c;以及设置多个本地站点的能力。 XAMPP是一…

34-5 CSRF漏洞 - CSRF分类

环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 1)GET 类型 传参: 参数连接在URL后面 POC构造及执行流程: 构造URL,诱导受害者访问点击利用利用标签进行攻击: 构造虚假URL,在链接上添加payload抓包获取数据包,通过CSRF POC…

ping命令返回无法访问目标主机和请求超时浅析

在日常经常用ping命令测试网络是否通信正常&#xff0c;使用ping命令时也经常会遇到这两种情况&#xff0c;那么表示网络出现了问题。 1、请求超时的原因 可以看到“请求超时”没有收到任何回复。要知道&#xff0c;IP数据报是有生存时间的&#xff0c;当其生存时间为零时就会…

K8s学习七(服务发现_2)

Ingress Service 主要用于集群内部的通信和负载均衡&#xff0c;而 Ingress 则是用于将服务暴露到集群外部&#xff0c;并提供灵活的 HTTP 路由规则。在实际应用中&#xff0c;它们通常结合使用&#xff0c;Service 提供内部通信和负载均衡&#xff0c;Ingress 提供外部访问和…

植物糖基转移酶数据库-23年-地表最强系列-文献精读-6

pUGTdb: A comprehensive database of plant UDP-dependent glycosyltransferases pUGTdb&#xff1a;植物UDP依赖糖基转移酶的全面数据库 一篇关于植物糖基转移数据库的综述&#xff0c;地表最强&#xff0c;总结的最全面的版本之一&#xff0c;各位看官有推荐请留言评论区~…

自定义复选款与单选框,input

注&#xff1a;字体文字取自bootstrap字体库https://icons.bootcss.com/icons <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.checkbox-com,.radio-com {position: relative;display: inlin…

javaWeb物流信息网的设计与实现

摘要 本文讲述了基于JSP物流信息网的设计与实现。该系统使用java语言开发&#xff0c;使系统具有更好的平台性和可扩展性。 该系统实现了用户登录、注册、查询快递信息、快递公司注册成为合作伙伴以及系统管理员对信息进行管理等功能。系统的主要界面会将所有的服务排列好&…

get请求搜索功能爬虫

<!--爬虫仅支持1.8版本的jdk--> <!-- 爬虫需要的依赖--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency>…

STM32一个地址未对齐引起的 HardFault 异常

1. 概述 客户在使用 STM32G070 的时候&#xff0c;KEIL MDK 为编译工具&#xff0c;当编译优化选项设置为Level0 的时候&#xff0c;程序会出现 Hard Fault 异常&#xff0c;而当编译优化选项设置为 Level1 的时候&#xff0c;则程序运行正常。表面上看&#xff0c;这似乎是 K…

Python计算多个表格中多列数据的平均值与标准差并导出为新的Excel文件

本文介绍基于Python语言&#xff0c;对一个或多个表格文件中多列数据分别计算平均值与标准差&#xff0c;随后将多列数据对应的这2个数据结果导出为新的表格文件的方法。 首先&#xff0c;来看一下本文的需求。现有2个.csv格式的表格文件&#xff0c;其每1列表示1个变量&#x…