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

【C语言】指针、多维数组零碎知识点


🌈 关于C指针和数组 相关的东西 今天被狠狠整顿了,现在回忆整理一下相关的知识点,既作分享,也加强记忆。本blog需要有基本的指针和数组相关的知识储备

文章目录

  • 提要
  • 1.二维数组
    • 关于二维数组和指针的指针
      • :herb:对于一维数组而言
      • :ear_of_rice:对于二维数组
  • 2. int*c =((int *)&a);
  • 3. float 类型 用%d读 出现的0.0000问题

提要

下面是学习的点。配合代码食用更佳~🌞

  1. 二维数组 存储形式和一维数组一样
  2. a[2] [3]是左值是因为a[2] [3]等价于 * (a+2* 4* sizeof(int)+3*sizeof(int))
  3. (int)b【也就是强制转换后】是右值,数组名a等效于右值
  4. 关于 int*c =((int *)&a);
  5. int *c= (char *)a;
  6. 关于 float 类型 用%d读的时候 出现的0.0000问题

1.二维数组

首先二维数组 我们知道是a[m] [n]这样的形式,其实就是数组的数组,可以理解为类似于矩阵的形式。

🤔那二维数组的存储方式和一维数组一样具体怎么理解?也就是二维数组和一维数组一样,是连续的存储空间。下面用一个代码展示一下。

#include<stdio.h>
int main(void){int a[2][3]={{1,2,3},{4,5,6}};printf("a[0]:%p\n",a[0]);printf("a[0][1]:%p\n",&a[0][1]);printf("a[0][2]:%p\n",&a[0][1]);printf("a[0][3]:%p\n",&a[0][3]);printf("a[1]:%p\n",&a[1]);printf("a[1][0]:%p\n",&a[1][0]);printf("a[1][1]:%p\n",&a[1][1]);return 0; 
}

思考一下,给出答案

也许有人会问a[0] [3]不是越界了嘛?我的理解: 但是其实越界这个概念的提出只是因为防止在连续的存储空间内没有这个变量,或者更改了其他的变量。而在这里,也就是连续的存储空间里,a[0] [2]下个值 在我们看来是a[1] [0],但其实写成a[0] [3]也没有关系,表示的就是a[0] [2]下个连续的地址。所以这边a[1] [0]和a[0] [3]是同一个东西。

答案如下~ 二维数组的存储形式 以sizeof(int) 个单位 依次递增,其存储形式表现的和一维数组是一样的形式。

a[0]0061FEFC
a[0][1]0061FF00
a[0][2]0061FF04
a[0][3]0061FF08
a[1]0061FF08
a[1][0]0061FF08
a[1][1]0061FF0C

关于二维数组和指针的指针

我们知道,一维数组也就是a[],其数组名a是该数组的首地址,而指针变量是存储地址的变量类型,所以这个数组名a也可当作指针变量使用,那么二维数组是否也有类似的形式?

🌿对于一维数组而言

int d[3]={1,2,3};
int *p2=d;printf("*(p2+1):%d\n",*(p2+1));
printf("*(p2+2):%d\n",*(p2+2));
printf("*(d+1):%d\n",*(p2+1));
printf("*(d+2):%d\n",*(p2+2));printf("address:(p2+1):%d\n",(p2+1));
printf("address:(p2+2):%d\n",(p2+2));
printf("address:(d+1):%d\n",(d+1));
printf("address:(d+2):%d\n",(d+2));

此时答案应该显而易见。由于p是指向a的指针,也就是p存储的值是a的地址,a也可当作指针变量使用,所以他俩的地址一样,解引用后得到的值也一样。

*(p2+1):2
*(p2+2):3
*(d+1):2
*(d+2):3
address:(p2+1):6422264
address:(p2+2):6422268
address:(d+1):6422264
address:(d+2):6422268

🌾对于二维数组

🤔依葫芦画瓢,那么怎么表示指向一个二维数组的指针变量,同时也可以用这个指针变量达到和类似二维数组表现形式一样的效果呢?

设有二维数组int a[3] [4];那么是不是也声明一个指针的指针,类似于int** p=a?

非也非也。

上文提到,二维数组存储形式和一维数组一样,二维数组的存储形式以sizeof(int) 个单位 依次递增,其存储形式表现的和一维数组是一样的形式。而int ** p是指针的指针,具体而言,p是一个指针,假设它存储的是地址A,而这个A是另一个指针变量的地址,于是用 ** 表示指针的指针。二维数组是和一维数组一样的存储形式,即顺序存储形式,也就不能用这种** p直接进行表示。

具体也可以试试看。 ** p如果指向a的地址,那么 p第一次解引用是a[0] [0] ,第二次解引用呢?没有地址可以给他解引用了,所以这样肯定是不行的。

*指向二维数组的指针可以表示为 int (p)[4] = a;

也就是指向数组的指针,具体而言,这个p是一个指针变量,它指向int[4]类型的数组;p+1表示的是 从基地址a[0] [0] 开始向下偏移1个单元,这一个单元包含4个int变量,也就是4个sizeof(int);二维数组a[3] [4]可以看作是含有3个单元,其中这的每个单元含有4个int类型的变量。所以总共有3 *4 个sizeof(int)

	int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};int (*p1)[4]=a;printf("p1:%p\n",p1);printf("a:%p\n",a);printf("a[0][0]:%p\n",&a[0][0]);printf("------------------\n");printf("p1+1:%p\n",p1+1);printf("a+1:%p\n",a+1);printf("a[0][4]:%p\n",&a[0][4]);printf("------------------\n");printf("p1+2:%p\n",p1+2);printf("a+2:%p\n",a+2);printf("a[1][4]:%p\n",&a[1][4]);printf("------------------\n");printf("*(p1+1):%p\n",*(p1+1));printf("*(a+1):%p\n",*(a+1));printf("a[1][0]:%p\n",a[1]);printf("------------------\n");printf("*(*(p1+1)+1):%d\n",*(*(p1+1)+1));printf("a[1][1]:%d\n",a[1][1]);

答案如下~记得自己多敲几遍。

p1:0061FEE8
a:0061FEE8
a[0][0]:0061FEE8
------------------
p1+1:0061FEF8
a+1:0061FEF8
a[0][4]:0061FEF8
------------------
p1+2:0061FF08
a+2:0061FF08
a[1][4]:0061FF08
------------------
*(p1+1):0061FEF8
*(a+1):0061FEF8
a[1][0]:0061FEF8
------------------
*(*(p1+1)+1):5
a[1][1]:5

2. int*c =((int *)&a);

int a=9;
int *p3=(int*)&a;
int *p4=(char*)a;
printf("*p3:%d\n",*p3);
printf("address: p3 :%p\n",p3);
printf("address: a :%p\n",&a);
printf("==============================\n");

第二行:这句话的意思是把a转换为一个int*的指针,这个指针变量存储的是3,这个变量的地址还是 a的地址。最后赋值给c

第三行:意思是把a强制转为char*的变量,注意,不管是什么指针,它都是8个字节的,所以它就把a,也就是3,作为 char *使用,存储的是3这个值,也就是指向的地址是3,而这个变量a的地址还是原来的地址。最后赋值给d。


结果

*p3:9
address: p3 :0061FED4
address: a :0061FED4

3. float 类型 用%d读 出现的0.0000问题

一切从一个程序说起,还是有点坑的

#include<stdio.h>
int main(void){float a=999897.777;int b=a;printf("%d,%f,%d,%f\n",b,a,a,b);return 0; 
}

🤔仔细想想最后输出什么;


999897,999897.750000,-2147483648,0.000000

这段代码其实比较基础。

首先,前面几个不难得到。

int b=a; 

进行了一次隐式的转换,也就相当于int b=(int) a ,所以此时b=3;

前面的第一个b 和 a不疑惑。第三个值,a等于一个负值,其实也不难理解,由于浮点数存储的形式和整型是不一样的,所以它读到的整形变量上是一个赋值不奇怪。

最后一个0.00000就比较难理解了,需要和底层硬件联系起来。

🐳具体解答可以看看这篇blog

总结一下就是 由于float 和 int 存储形式的差异,导致最终的结果为0;

flaot 存储的形式是 类似 整数+指数 这样的类型的,比如312.2怎么存储的?就是把3122放入整数中,然后指数为-1,也就类似于3122* 10(-1) 这样存储的 。

🌈 ok 完结~

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Linux 操作系统速通
  • 蒲公英G5-2250路由器之收集各种硬件的配置页面
  • 初见scikit-learn之基础教程
  • langchain调用讯飞星火大模型3.5和4
  • C++入门 | auto关键字、范围for、指针空值nullptr
  • dynamic-datasource+Mybatis多数据源使用
  • ctfhub Bypass disable_function
  • 论文辅导 | 基于概率密度估计与时序Transformer网络的风功率日前区间预测
  • 测试总结8/6
  • 08.SQL注入-下(超详细!!!)
  • 如何在SQLite中实现自动时间戳
  • 【C++ | 泛型编程】C++函数模板详解(定义、使用、特化、重载)
  • 工具学习_CONAN_Consuming Packages
  • 如何在 Debian 上安装运行极狐GitLab Runner?【一】
  • Hadoop入门:构建你的第一个大数据处理平台
  • CSS中外联样式表代表的含义
  •  D - 粉碎叛乱F - 其他起义
  • JavaScript HTML DOM
  • JAVA之继承和多态
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • session共享问题解决方案
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • SwizzleMethod 黑魔法
  • uva 10370 Above Average
  • 关于for循环的简单归纳
  • 利用DataURL技术在网页上显示图片
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 事件委托的小应用
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 在Unity中实现一个简单的消息管理器
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • FaaS 的简单实践
  • 从如何停掉 Promise 链说起
  • # SpringBoot 如何让指定的Bean先加载
  • #QT(TCP网络编程-服务端)
  • #Z2294. 打印树的直径
  • ( )的作用是将计算机中的信息传送给用户,计算机应用基础 吉大15春学期《计算机应用基础》在线作业二及答案...
  • (52)只出现一次的数字III
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (生成器)yield与(迭代器)generator
  • (实测可用)(3)Git的使用——RT Thread Stdio添加的软件包,github与gitee冲突造成无法上传文件到gitee
  • (四)c52学习之旅-流水LED灯
  • (一)认识微服务
  • .bat批处理(十一):替换字符串中包含百分号%的子串
  • .form文件_一篇文章学会文件上传
  • .Net Core 中间件与过滤器
  • .net framework 4.8 开发windows系统服务
  • .NET Framework、.NET Core 、 .NET 5、.NET 6和.NET 7 和.NET8 简介及区别
  • .NET(C#) Internals: as a developer, .net framework in my eyes
  • .net6使用Sejil可视化日志
  • .NET框架设计—常被忽视的C#设计技巧
  • .php文件都打不开,打不开php文件怎么办