当前位置: 首页 > news >正文

C语言指针和数组相关习题

目录

  • sizeof和一维int数组
  • sizeof和一维char数组
  • strlen()和一维char数组
  • sizeof和字符串
  • strlen()和字符串
  • 指针变量指向字符串字面常量
  • 易错点sizeof('a'):sizeof是操作符 当心整型提升
  • sizeof和二维数组
    • 复习一下相关知识点
    • 练习题
  • 一个离谱的错误
  • 指针1
  • 指针2
  • 指针3
  • 指针4
  • 指针5
  • 指针6
  • 指针7
  • 指针8

sizeof和一维int数组

  • []的优先级比&高 所以&a[0]相当于&(a[0]) 取出了第一个元素的地址
  • a+0 既没有单独放在sizeof内部 也没有单独& 所以a就表示首元素地址 是一个int* a+0仍然是首元素地址 还是int* 也就是4/8
  • 同理 *a 也没有两个单独 所以就是首元素地址的解引用
  • sizeof(*&a):之前说过 对于一个数组指针解引用 结果就当做数组名来用 &a就是数组指针 *&a得到的就是数组名a *&a同样遵循两个单独的规则
  • &a+1 得到的结果不会改变:1.指针类型 2.权限
    所以 &a+1得到的还是一个数组指针(但本质也是个指针,地址)
  • 拓展:所以sizeof(*(&a+1)) 仍然相当于对数组指针解引用 得到的是一个"越界数组"的数组名 单独放在sizeof里 结果还是16
  • sizeof(sizeof(a+1)) === 4 不管内部sizeof在算什么 他的返回值肯定是size_t 即unsigned int 大小肯定是4字节

在这里插入图片描述

sizeof和一维char数组

这个就很简单了 都很明显
sizeof的核心就是 根据类型 在编译阶段就判断出大小了(字节)
在这里插入图片描述

strlen()和一维char数组

和上一题一模一样的数组 这次换成strlen
在这里插入图片描述

这里唯一要注意的就是strlen(*arr)
strlen接收的是地址!!
*arr其实得到字符a 本质上是97
strlen(97) 因为它接收的是一个地址 所以把97理解成地址了 非法访问!
0x00000061就等于十进制的97 97被理解成某个地址了 非法!!
那strlen(arr[1]) 也就是strlen(98) 是一样的道理
在这里插入图片描述

下面三个 &arr的地址值和&arr[0]和arr其实是一样的 只不过指针类型不一样
但是strlen是直接把你的值当做一个字符的地址的 也就是char* 然后从这个地址开始寻找\0
在这里插入图片描述
在这里插入图片描述

sizeof和字符串

在这里插入图片描述

  • 主要是字符串自带一个结束标志:‘\0’

在这里插入图片描述

strlen()和字符串

  • 注意倒数第二个 \0也是数组的一份子 +1把整个数组都跳过了 包括\0
    在这里插入图片描述

指针变量指向字符串字面常量

注意 这不是数组的形式了 p就是一个指针变量
在这里插入图片描述

下面就要注意strlen(&p)
&p是指针变量p的地址 跟"abcdef"毫无关系
随便拿了个地址就从那里开始找\0 肯定是随机值
在这里插入图片描述

易错点sizeof(‘a’):sizeof是操作符 当心整型提升

当成特例记住就行了 不要影响前面正常的理解

这个a的类型明明就是char 很难解释
只能这么理解:
sizeof就是个 操作符
sizeof(‘a’) 这就算char类型的’a’参与运算了
之前我们说过 这种情况就会发生整型提升

在这里插入图片描述

所以’a’还是会被sizeof理解成int类型 故答案是4
在这里插入图片描述

下图是一个类似的案例
在这里插入图片描述

● 其实不需要过于纠结 sizeof就看做求类型的大小
● 说明*p还是理解成char的
● 但是’a’被理解成int(97) 也有可能是’a’发生了整型提升
● 其实如果把这个文件改成.cpp 就是1了
所以不要纠结 知道sizeof就是求类型大小的就行

在这里插入图片描述
看一下CHatGPT的解释
认为’a’的本质是int 我觉得这个更合理
在这里插入图片描述

sizeof和二维数组

复习一下相关知识点

想象中的二维数组:
在这里插入图片描述

实际上的二维数组:
● a是整个二维数组的数组名 a的类型是数组指针
● 对数组指针解引用 得到的东西看做数组名 遵循两个单独 比如*&a
● arr[i]也是第i行一维数组的数组名
*(arr+i) == arr[i] 也表示第i行一维数组的数组名
● arr[i]和*(arr+i) 也遵守两个单独原则
在这里插入图片描述

练习题

a[0] == *(a+0) 对数组指针解引用 得到当前数组的数组名
就把他当成数组名来看待 也满足数组名所谓的"两个单独"
而且 指针+1不会改变指针的类型
a[0]+1 就是数组名+1 没有两个单独 所以就是当前一维数组的首元素地址+1
其实a[0]+1得到的是第一行一维数组的第二个元素的地址
在这里插入图片描述

● sizeof(a) 二位数组名单独放在sizeof里 表示整个二维数组大小(其实应该理解为 表示a[3][4]这种类型的大小)
●sizeof(a+1) 没有两个单独 所以a表示二维数组的首元素地址 即一维数组指针 +1跳过一个一维数组
且+1之后之类型和权限不变 变成了指向第二行一维数组的数组指针
●之前说过 把数组指针解引用理解成数组名 sizeof(*(a+1)) a+1是数组指针 解引用之后是数组名 其实就是sizeof(第二行一维数组的数组名) 也就是sizeof里面单独放了数组名(第二行一维数组的数组名) 算到16
或者从语法层面理解 *(a+1) = a[1] a[1]就是第二行的数组名 而且是单独放在sizeof里的
a+1 == &a[0]+1 都表示指向第二行一维数组的数组指针
&a[0]即&数组名 数组名单独在&之后 得到整个数组的地址 就是数组指针(指向第一行一维数组)
● &a[0]是数组指针 +1指针类型不变 *(&a[0]+1) 是对一个一维数组指针解引用 得到数组名 单独放在sizeof里 就是16
● sizeof(*a) 数组名a没有单独放在里面 所以a表示首元素地址(数组指针) *a对一维数组指针解引用 得到第一行一维数组的数组名 *a整体又是单独放在sizeof里的 相当于数组名单独放在sizeof内部 所以求的整个第一行一维数组的大小 即16
● 或者理解成:*a = *(a+0) = a[0]--->第一行数组名
● a[3]的确是越界了(但并没有解引用 所以不报错) 但是sizeof只关心类型 a[3]仍然被解读成*(a+3) 即对数组指针解引用 相当于把数组名单独放在sizeof内部 所以还是16
在这里插入图片描述

sizeof只关心类型 不会真的访问那块空间的 所以不会报错的
在这里插入图片描述

一个离谱的错误

一心想着&数组名 “单独"跟一个数组名
我就想着 如果不是单独 是不是就是二级指针了 居然写出了这种代码…
其实之前已经探讨过这个"牛角尖”
arr作为数组首元素地址 本质也是个指针/地址 也是个常量啊?
为什么就可以写&arr了 arr不也是常量吗?
所以才说他是特殊情况呢!!!
只有单独的时候才能用&+arr啊!!!
而且"单独"&arr 取出的就是整个数组的地址
对于一维数组来说 那就是一维数组指针
在这里插入图片描述

指针1

&a 单独+数组名 是一种特殊情况 取出整个数组的地址
数组指针+1 跳过一整个数组
但是跳完了类型又被强转成int*了 -1退后一个int 解引用访问一个int
答案:2,5
在这里插入图片描述

指针2

可能一上来第一个就算错了 算成:100001 这就错了 这不是数值的计算
这题考察的是:

  1. 指针+1 跳过几个内存单元(几个字节) 这取决于指针类型
  2. 数值+1 那就是单纯的+1 学了指针不要忘记正常的情况了
  3. 结构体内存对齐 怎么计算结构体的大小(才知道结构体指针+1跳过几个字节)
  4. 32位机器 指针4字节 %p打印即8个十六进制位 所以答案还要自己补0!! 细节!!
  5. 如果用 %x单纯打印16进制 前面的0没有数值意义 就会省略

答案:00100014,00100001,00100004
第二个这个地址就被当成一个无符号的数了(0x100000只不过是用16进制来表示了一个整数) 进行的是数值± +1那就是单纯的+1
在这里插入图片描述
在这里插入图片描述

指针3

内存中的存储(小端):
01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
ptr1[-1] = *(ptr1-1)
%x是打印十进制对应的十六进制补码 只打印有效位(高位没意义的0不打印)
%p其实也是打印十进制对应的十六进制补码 不过我们一般用%p专门打印地址 地址肯定是4字节 也就是8个十六进制位 不足8位会补齐
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ptr1-1会跳过一个int 指向04的内存单元
再*(ptr-1) 权限是一个int
又拿到一个int 就是4
在这里插入图片描述
在这里插入图片描述

指针4

注意逗号表达式!!! 这是不完全初始化!!!
arr[0] 即第一行元素的数组名(他也遵守两个单独的规则)
int *p = a[0] 类似之前一维数组写的int* parr = arr
这里的a[0]并没有两个单独 就表示首元素地址 把首元素地址赋给p了
p指向 [1,3]这个一维数组的首元素地址 p[0] = *(p+0) = *p = 1
在这里插入图片描述

指针5

这里主要就是要知道 p[4][2] 和 a[4][2]指向哪里去了?
a[4][2]很好理解 这里对于p[4][2] 有两个看待角度:

  1. p[4][2] 即在p的视角下的二维数组的第五行第三列 对于p来说 每一行应该是四个元素 所以找到第五行就是每次跳过四个元素 跳四次 然后再找第三个元素 只要画好图 很好找
  2. 从理论上理解 p[4][2] = *(p+4)[2] = *(*(p+4)+2)
    p的类型是int(*)[4]的数组指针 p+1 每次跳过一个数组 即四个int 且类型保持不变 那么p+4 就是跳过四个数组 即16个int
    p+4之后 类型不变 还是数组指针 指向一个新的数组
    *(p+4) 对数组指针解引用 得到当前数组的数组名 那么*(p+4)[2]也就是当前数组第三个元素
    如果要进一步理解*(*(p+4)+2)
    这里*(p+4)这个数组名没有单独规则 所以就表示当前数组的首元素地址
    *(p+4)+2 相当于arr+2 指向第三个元素 再解引用 就拿到第三个元素

下面又把元素的地址取出来相减了
指针-指针的绝对值求的是隔了几个元素
算到-4

在这里插入图片描述
在这里插入图片描述

打印的时候
不管是%d 还是%p %x %X 都是针对存的补码去打印
只不过%d打印的时候 把补码当做有符号数打印 需计算原码
而地址没有什么原反补 就是直接把存起来的补码 当成一个地址打印(地址一般用16进制表示)
在32位机器 也就是打印8个十六进制位
在这里插入图片描述
%x打印的也是二进制补码
在这里插入图片描述

指针6

arr是数组指针 arr+1跳过一整个数组 *(arr+1) 其实就是得到了第二个数组的数组名
*(arr+1)又等于arr[1]arr[i]得到的就是第i个一维数组的数组名
所以ptr2 = (int*)arr[1] 即(int*)第二个一维数组的数组名
在这里插入图片描述

指针7

int* *p p的类型是int**--(二级)指针 p+1跳过1个int*(地址)
● 数组里放的分别是:w的地址 a的地址 a的地址
● 数组名表示首元素地址 也就是w的地址的地址 --二级指针
● pa++ 即跳过一个char*(地址) 把图画好 解引用pa得到的其实是at的a的地址在这里插入图片描述

在这里插入图片描述

指针8

  • 注意++操作符 是有副作用的 会真的改变值
    在这里插入图片描述
    在这里插入图片描述

http://www.mrgr.cn/news/63039.html

相关文章:

  • UE5动画控制 基础
  • 状态模式(State Pattern)
  • 低代码可视化-uniapp slider区间组件-代码生成器
  • SASS转换成CSS步骤
  • 面试域——岗位职责以及工作流程
  • 火山引擎VeDI数据服务平台:在电商场景中,如何解决API编排问题?
  • Python中如何处理异常情况?
  • C++算法练习-day30——111.二叉树的最小深度
  • C++算法练习-day29——104.二叉树的最大深度
  • C语言 | Leetcode C语言题解之第523题连续的子数组和
  • Podman+Minikube:MacBook 运行 Kubernetes 最佳实践
  • vmvare启动freebsd操作系统密码忘记了怎么办?
  • 哪里可以找到无版权抖音视频素材?
  • lanqiaoOJ 1110:小王子单链表 ← STL list
  • Python | Leetcode Python题解之第524题通过删除字母匹配到字典里最长单词
  • mysql 的内连接、左连接、右连接有什么区别?
  • 3000字帮你彻底搞懂Java抽象类与接口的区别(含JDK8接口新增三种方法与丰富案例)
  • 如何在Ubuntu 18.04上使用uWSGI和Nginx为Flask应用提供服务
  • 【数据结构-邻项消除】力扣1717. 删除子字符串的最大得分
  • 如何找到车在路上行驶的视频素材
  • 数据结构之顺序表(C语言)
  • Java | Leetcode Java题解之第523题连续的子数组和
  • JavaScript实现将阿拉伯数字转换成中文或大写中文
  • 通过软盘拷贝文件
  • 什么是指针数组 和 数组指针
  • antd 5X中 tree属性结构,自定义菜单,右键菜单实现方式