取消引用运算符告诉多维数组引用期间编译器要做什么?

如何解决取消引用运算符告诉多维数组引用期间编译器要做什么?

我一直在研究多维数组和括号符号,并尽力对解引用,指针类型和指针算术之间的相互作用有一个概念上的理解。

对于此问题,请考虑以下任意3D阵列参考:

    arr[i][j][k]

现在,我相信以下转换是等效的(我运行了一些代码示例,我相信它们可以确认准确性):

    *(*(*(arr+i)+j)+k)

我运行的代码如下:

#include <stdio.h>

int main(void) {

    char arr[2][3][4] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x' };

    printf("%c \n",arr[1][1][1]);

    printf("%c \n",*(*(*(arr+1)+1)+1));

    return 0;
}

您可以更改printf语句中的值(只要ijk的值在两者之间相同)。无论如何,他们始终同意在命令终端上打印出什么字母。

下图描述了我获得这个假定的等效答案的方式(对不起,我使用了数学堆栈交换编写软件,因为它使一切变得更简单了……如果指针算术的表示法有些混乱,我很抱歉。)


Derivation


因此,我的主要困惑来自解引用运算符*。坦率地说,我不明白它告诉编译器要做什么

举一个简单的例子,假设字符数组arr的基地址为100。

arr实际上是指向类型char[3][4]的2D矩阵的指针。我认为这意味着(因为一个字符需要1个字节),代码arr + 1实际上是在说100+12。重写方程式,然后我将得到:

*(*(*(112)+1)+1)。我相当确定,解除引用运算符(在112的左侧)比+符号(在112的右侧)具有从左到右的优先级。

根据我在一维情况下使用取消引用符号的经验,这将产生存储在112个存储单元中的值。 但这在当前情况下似乎是错误的。显然,我不了解取消引用操作在这种情况下的行为。任何帮助将不胜感激!

干杯〜

解决方法

您需要了解两件事:

  • 数组不是指针,即使在大多数情况下它们会自动转换为指针。

  • 与一维数组相比,多维数组得到零特殊处理。它们一维数组,其中每个元素也是一个数组。


执行*(*(*(arr+1)+1)+1)时,arr将自动转换为指向其第一个元素的指针。该指针的类型为char(*)[3][4](指向char[3][4]的指针)。向其添加1会使指针的值增加1*sizeof(char[3][4]) == 12。您似乎已经知道这一点。

取消对结果指针的引用会为您提供类型char[3][4]的左值,继而衰减到类型为char(*)[4]的指针&arr[1][0]。将1添加到该指针后,其值将1*sizeof(char[4])递增&arr[1][1]

解引用结果指针将为您提供类型char[4]的左值。它也衰减为类型为char *的指针&arr[1][1][0]。向其添加1后,其值将增加1*sizeof(char)并等于&arr[1][1][1]。然后,最终的取消引用将为您提供arr[1][1][1]的值。

,

否,C中的指针不是整数,它们具有不同的类型,并且与数组索引运算符或指针算法一起使用的指针必须引用完整类型的对象,即,其大小为已知的使用位置。

声明

char arr[2][3][4];
可以读取

arr[i][j][k]类型为char

它还表明arr本身的类型为char[2][3][4]。每个第一级元素,即arr[i]的类型为char[3][4],每个第二级元素的类型为char[4]。如果您对这些类型进行sizeof

  • sizeof(char)是1
  • sizeof(char[4])是4
  • sizeof(char[3][4])是12
  • sizeof(char[2][3][4])是24

现在,在几乎 any 上下文中,数组类型的表达式被称为 decay 指向 first 元素的指针。这也适用于arr。由于arr的第一个元素是arr[0],并且从上面的类型或arr[0]arr[i]的元素,即char[3][4],因此结果类型是指向char[3][4]的指针;在C中用(char *)[3][4]写。

如果向该指针添加整数,则结果指针将指向该类型 的第n个(从0开始)对象。

arr + 0将导致一个指向该数组的 first char[3][4]子数组的指针; arr + 1 second ,依此类推。另外,arr + n指向内存位置(字节),该位置距n * sizeof(char[3][4])的开头n * sizeof(arr[0])个字节(也是arr)。 / p>

现在,如果我们取消引用该指针,例如*(arr + 1),结果表达式将是类型为char[3][4] array 。但是,该值将立即衰减为指向该数组第一个元素的指针。该数组的元素类型为char [4],指针类型为char (*)[4]

如果我们如上所述添加一个整数,我们将获得一个指向该数组的第n个char[4]子数组的指针;即使用(*(arr + 1) + 1)。现在,如果取消引用指针*(*(arr + 1) + 1),我们将得到类型为char[4]的表达式,但它会立即衰减为指向第一个元素的指针。由于char[4]的元素是字符,因此类型将是简单明了的Garak ... err char *

现在,如果我们向其添加一个整数,我们将获得一个指向char[4]数组中第n个 element 的指针(例如(*(*(arr + 1) + 1) + 1),如果我们取消引用({ {1}}),我们得到类型*(*(*(arr + 1) + 1) + 1)的左值,它在数组中指定此特定字符。


那么为什么需要取消引用运算符?当然要引用子对象。

如果删除星星,char实际上等于(((arr + 1) + 1) + 1),它是指向arr + 3的指针,即 4th {{1 }} arr[3]的子数组。由于char[3][4]仅具有 2 个这样的子数组,因此它不仅无法执行您想要的操作,而且会导致可怕的不确定行为

>

TL; DR:

鉴于上述定义arrarr,在衰减之后,将导致指向相同内存位置但具有不同类型的指针。

,

下标数组和指针的含义相同:a[i]告诉编译器计算数组第i个元素的地址。如果在右值中使用a[i],则会读取该地址。

如果a是指针,则此计算需要读取指针的内容,并向其添加数组元素大小的i倍。

如果a是一个数组,则此计算仅涉及将数组元素大小的i乘以数组的地址。

在两种情况下,a[i]都可以重写为*(a+i),因为如果a是一个数组,它会自动衰减为指向表达式{{1}的第一个元素的指针}。从概念上讲,它等效于:

a+i

请注意, int a[10]; int i,x; x = a[i]; int *a_ = &a[0]; x = *(a_ + i); 中的*会导致*(a+i)计算的地址被读取,如果该值是在右值上下文中使用的,例如a+i或被写入如果它出现在左值上下文中:x = *(a+i);。语句*(a+i) = x;既不读取也不写入数组元素(除非将*(a+i);声明为a)。

在您的示例中,volatilechar arr[2][3][4]arr[0][0][0]arr[0][0]arr[0]具有相同的地址,只是它们的类型不同。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-