指针的深入理解(六)

指针的深入理解(六)

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


文章目录

  • 指针的深入理解(六)
    • 前言
    • 一. 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

后言

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

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

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

相关文章

前端html+css+js常用总结快速入门

&#x1f525;博客主页&#xff1a; A_SHOWY&#x1f3a5;系列专栏&#xff1a;力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 学习前端全套所有技术性价比低下且容易忘记&#xff0c;先入门学会所有基础的语法&#xff08;cssjsheml&#xff09;&#xff…

深度挖掘商品信息,jd.item_get API助您呈现商品全面规格参数

深度挖掘商品信息&#xff0c;特别是在电商平台上&#xff0c;对于商家、开发者和用户来说都至关重要。jd.item_get API作为京东开放平台提供的一个强大工具&#xff0c;能够帮助用户轻松获取商品的全面规格参数&#xff0c;进而为商品分析、推荐、比较等提供有力的数据支撑。 …

using和typename在C++中的用法

using关键字有两个主要用途&#xff1a; 1.类型别名&#xff1a;使用using可以为类型创建新的名称&#xff0c;这在模板编程中尤其有用。 using integer int; integer a 5; // 这里的integer就是int类型2.命名空间&#xff1a;using可以用来引入命名空间中的名字&#xff0c…

Liquid的Covenants:处理比特币脚本中的金额

1. 引言 Covenants契约是一种允许introspection自省的结构&#xff1a; 交易output可以对花费其的交易施加条件&#xff08;超出特定的“必须提供自身的有效签名和特定的公钥”&#xff09;。 Rusty Russell 之前研究过Covenants: Examining ScriptPubkeys in Bitcoin Scrip…

两相欠压继电器 WY-35A3 额定输入电压100V 导轨安装 JOSEF约瑟

系列型号&#xff1a; WY-35A4电压继电器&#xff1b;WY-35B4电压继电器&#xff1b; WY-35C4电压继电器&#xff1b;WY-35D4电压继电器&#xff1b; WY-35A4D电压继电器&#xff1b;WY-35A4T电压继电器&#xff1b; WY-35B4D电压继电器&#xff1b;WY-35B4T电压继电器&#xf…

人工智能时代过失犯理论的挑战与应对—以自动驾驶汽车交通肇事为例

内容提要以自动驾驶汽车为代表的人工智能产品致害所涉犯罪主体复杂多样、前置性规范缺失, 以及人工智能产品固有的自主与黑箱特性等问题给过失犯理论带来了变革的压力与挑战。传统过失犯理论、新过失犯理论以及客观归责理论都无法解决人工智能产品致害所涉过失犯罪认定问题。人…

【VMware】虚拟机及镜像Ubuntu安装

Vmware 一.VM是什么&#xff1f;有什么用&#xff1f;二.下载VMware Wworkstation Pro三.安装虚拟机四.安装镜像 一.VM是什么&#xff1f;有什么用&#xff1f; vmware是一款运行在windows系统上的虚拟机软件&#xff0c;可以虚拟出一台计算机硬件&#xff0c;方便安装各类操作…

K8s学习七(服务发现_2)

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

网络工程师笔记18(关于网络的一些基本知识)

网络的分类 介绍计算机网络的基本概念&#xff0c;这一章最主要的内容是计算机网络的体系结构-ISO 开放系统互连参考模型&#xff0c;其中的基本概念&#xff0c;例如协议实体、协议数据单元&#xff0c;服务数据单元、面向连接的服务和无连接的服务、服务原语、服务访问点、相…

蓝桥杯练习题 —— 高精度加法(python)

python优势 # encoding utf-8 # 开发者&#xff1a;xxx # 开发时间&#xff1a; 16:48 # "Stay hungry&#xff0c;stay foolish."a int(input()) b int(input())print(a b) 正常 # encoding utf-8 # 开发者&#xff1a;xxx # 开发时间&#xff1a; 16:48 #…

大数据分层存储架构:ODS、DWD、DWM与DWS详解

在大数据领域中&#xff0c;ODS、DWD、DWM和DWS代表了数据仓库的不同层次&#xff0c;它们共同构成了大数据的分层存储结构。这种结构的设计有助于提高数据查询效率&#xff0c;降低成本&#xff0c;并满足不同的业务需求。 ODS&#xff08;Operational Data Store&#xff09…

计算机视觉领域主流优秀的模型的用处与区别,优劣。复合缩放方法,深度可分离卷积

目录 计算机视觉领域主流优秀的模型的区别,优劣 YOLO (You Only Look Once) ResNet、EfficientNet 优劣与应用场景

1.k8s简介

目录 k8s是什么 k8s不是什么 云原生 微服务 整体式架构与微服务架构 微服务的特性 微服务的优势 k8s是什么 Kubernetes 是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快…

除了sql外还有那些查询语言

除了SQL&#xff08;结构化查询语言&#xff09;外&#xff0c;还有许多其他的查询语言&#xff0c;包括但不限于XQuery&#xff08;对XML的查询语言&#xff09;、MDX&#xff08;多维查询语言&#xff0c;用于分析数据仓库&#xff09;、DQL&#xff08;数据查询语言&#xf…

聊一聊,JMeter分布式性能测试!

在做后端服务器性能测试中&#xff0c;我们会经常听到’分布式’。但你是否了解分布式呢&#xff1f;今天&#xff0c;我们就来给大家讲讲&#xff0c;在企业实战中&#xff0c;如何使用分布式进行性能测试&#xff0c;实战过程中&#xff0c;又有哪些地方要特别注意&#xff1…

pyqtgraph 实时更新柱状图

import sys import numpy as np from PyQt5.QtWidgets import QApplication, QMainWindow import pyqtgraph as pgclass MainWindow(QMainWindow):def __init__(self):super().__init__()self.plot_widget pg.PlotWidget(title实时更新的柱状图)self.setCentralWidget(self.pl…

C++ //练习 11.22 给定一个map<string, vector<int>>,对此容器的插入一个元素的insert版本,写出其参数类型和返回类型。

C Primer&#xff08;第5版&#xff09; 练习 11.22 练习 11.22 给定一个map<string, vector<int>>&#xff0c;对此容器的插入一个元素的insert版本&#xff0c;写出其参数类型和返回类型。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具…

法向量估计

法向量估计 1. 求解点P法向量的原理2. 法向量估计的证明3. 为什么求点P的法向量&#xff0c;需要使用以P为中心的邻域内的点&#xff1f;4. 法向量估计的应用和思考5. 权重法向量估计 1. 求解点P法向量的原理 已知有一组点 P ( p 1 , p 2 , p 3 , . . . , p n ) , p i ∈ R 3…

算力在现实生活中的多方面应用!

算力在现实生活中的应用是多方面的&#xff0c;它已经成为推动现代社会发展的重要力量。 以下是算力在不同领域中的具体应用&#xff1a; 立即免费体验&#xff1a;https://gpumall.com/login?typeregister&sourcecsdn #分布式云服务#算力#GpuMall#GpuMall智算云#训练#…

零代码与低代码开发平台

1、什么是低代码开发平台&#xff1f;什么是零代码开发平台&#xff1f; 零代码开发平台&#xff1a; 指的是不需要写代码就能够快速开发出业务应用/系统的平台。我们在工作中使用的业务应用&#xff0c;主要提供数据收集、数据处理、数据流转和展示等功能。零代码开发平台能够…