在二维数组 A[m][n] 中,A 的值如何与 *A 相同?

如何解决在二维数组 A[m][n] 中,A 的值如何与 *A 相同?

我对二维数组的了解:

  1. 在数组中,数组名是指向第一个元素地址的指针
  2. 这里我们可以将 A 视为数组的数组,因此 A 将指向第 0 个一维数组
  3. 所以 A+i 将指向 A 的第 i 个元素
  4. *(A+i) 将指向 A 的第 i 个元素的第一个元素
  5. 那么在二维数组中 A+i 地址值应该与 *(A+i) 相同

但这对我来说没有意义 A 值如何与 *A 相同,有人可以告诉我这是如何在内存中工作的,我知道这是正确的,但我无法向自己解释

解决方法

声明

在数组中,数组名是指向第一个元素地址的指针

错误

对于任何数组,它的符号本身会衰减到指向它的第一个元素的指针。

因此对于您的数组 A,它将衰减到 &A[0]

如果你取消引用那个指针,就像 *A 发生的那样,那么你有 *(&A[0])。这与普通的 A[0] 相同。

因为你的数组 A 是一个数组数组,那么 A[0] 是一个数组,它反过来也会衰减到指向它的第一个元素的指针。所以 A[0] 会衰减到 &A[0][0]

所以 *A 将与 &A[0][0] 相同。

然而,对于不同的指针,类型有很大的不同。

以数组为例:

int A[3][4];

那么 &A[0] 将是一个指向由四个 int 值组成的数组的指针,或者 int (*)[4]。而 &A[0][0] 将是指向单个 int 值或 int * 的指针。


现在为什么所有这些指针看起来都一样,那是因为它们都指向同一个位置,也恰好与数组本身的位置相同(即&A,它将有类型int (*)[3][4])。

如果我们“绘制”它,它看起来像这样:

+---------+---------+---------+---------+---------+---------+-----+
| A[0][0] | A[0][1] | A[0][2] | A[0][3] | A[1][0] | A[1][1] | ... |
+---------+---------+---------+---------+---------+---------+-----+
^
|
&A
|
&A[0]
|
&A[0][0]

如您所见,所有三个指针都指向相同的位置,但如前所述具有不同的类型。

,

“在数组中,数组名是指向第一个元素地址的指针。”这不是真的。是时候忘记你曾经听过它了。这在一定程度上是正确的,在某些有限的情况下它可能是有用的解释,但迟早会引起比它可能提供的任何有用解释更多的混乱。

真正的真相是这样的:当你在表达式中询问数组的“值”时,你得到的是一个指向它的第一个元素的指针。

因此对于任何数组 A,如果您尝试像这样打印其值:

printf("%p\n",A);

你会看到一个指向数组第一个元素的指针。

但是你有一个二维数组。所以如果你请求 A,你会得到一个指向数组第一个元素的指针。但是当您要求 *A 时会发生什么?

好吧,如果 A 为您提供指向数组第一个元素的指针,那么 *A 会为您提供该指针的“内容”,它是数组的第一个元素数组,也就是……另一个数组!

如果您尝试获取“那个”数组的值,请说

printf("%p\n",*A);

你得到的是一个指向那个数组第一个元素的指针。

我认为你可以看到,对于二维数组,指向整个数组的指针将与指向数组中第一行的指针相同,与指向第一个元素的指针相同数组的第一行。


接下来的内容一开始可能有点令人困惑。我说,“当你在表达式中要求数组的“值”时,你得到的是一个指向它的第一个元素的指针。更正式地说,这意味着在表达式中,当您提到 A 时,它 100% 完全相同,就像您说的 &A[0] 一样。

因此,由于 * 有点取消 & 的效果,所以当您说 *A 时,它 100% 完全相同,就像您说 {{1} }.

以上适用于任何类型的数组。对于二维数组,事情会变得更有趣。

首先,对于二维数组,当我们查看 A[0]*A 时,它们中的任何一个都引用了另一个数组——二维数组数组的第一行。

所以 A[0] 为您提供了一个指向 A 的第一个元素的指针,该元素是另一个数组。
A 会为您提供一个指向第一行第一个元素的指针,该元素是一个实际的单元格。
因此表达式 *AA 将具有相同的指针值,它们具有不同的类型!
第一个类型为“指向任何数组的指针”,而第二个类型为“指向任何内容的指针”。

另见旧 question 6.12 中的 C FAQ list

,

如果您有一个数组,那么它在表达式中使用的指示符(例如用作 sizeof 运算符的操作数)会被转换为指向其第一个元素的指针。

如何为多维数组正确编写这样的指针?

假设你有一个多维数组

T a[N1][N2][N3][N4];

其中 T 是某种类型,N1N2N3N4 是子数组中元素的数量。然后要获得指向数组元素类型的指针,您可以像

一样重写数组
T ( a[N1] )[N2][N3][N4];

所以要获得指针,只需将记录 a[N1] 替换为记录 *p 就像

T ( a[N1] )[N2][N3][N4];
T ( *p )[N2][N3][N4] = a;

现在指针 p 指向数组 a 的第一个元素,其类型为 T [N2][N3][N4]

这里有一些例子

T ( a[N1] );
T ( *p ) = a; // that can be simplified like T *p = a;

T ( a[N1] )[N2];
T ( *p )[N2] = a;

T ( a[N1] )[N2][N3];
T ( *p )[N2][N3] = a;

等等。

在数组中,数组名是指向第一个元素地址的指针

C 标准(6.3.2.1 左值、数组和函数指示符)

3 除非是 sizeof 运算符或一元 & 的操作数 运算符,或者是用于初始化数组的字符串文字, 类型为“类型数组”的表达式被转换为 类型为“指向类型的指针”的表达式,指向首字母 数组对象的元素并且不是左值。如果数组对象 有寄存器存储类,行为未定义。

这里我们可以认为A是数组的数组,所以A会指向第0个1D 数组

是的,多维数组是数组元素依次是数组。

所以 A+i 将指向 A 的第 i 个元素

是的,在表达式 A + i 中,数组指示符被转换为指向其第一个元素的指针。所以使用指针算法,源表达式指向数组的第 i 个元素。

*(A+i) 将指向 A 的第 i 个元素的第一个元素

表达式 *( A + i ) 产生表达式 A + i 指向的对象的左值。如果 A 是二维数组,则表达式 *( A + i ) 生成位于源数组的第 i“行”中的一维数组。表达式 *( A + i ) 等价于表达式 A[i]

那么在二维数组中 A+i 地址值应该与 *(A+i) 相同

A + i 是指向数组 A 的第 i 个元素。如果 A 是二维数组,则表达式 *( A + i ) 生成数组的第 i 行,该行是一个-维数组。在表达式中使用的这个一维数组的指示符 *( A + I ) 依次转换为指向其第一个元素的指针。所以这两个指针A + i*( A + i )在隐式转换后最后一个表达式为指针将具有相同的值但不同的类型。

所以如果你有

T A[N1][N2];

那么表达式 A + i 的类型为 T( * )[N2]。取消引用像 *( A + i ) 这样的表达式,您将获得原始数组的第 i 个元素,它是类型为 T[N2] 的一维数组。反过来,表达式中使用的这个数组指示符被转换为其类型 T * 的第一个元素,并且两个指针 T( * )[N2]T * 将在原始数组占用的内存范围内具有相同的地址>

这是一个演示程序。

#include <stdio.h>

int main(void) 
{
    enum { N1 = 3,N2 = 5 };
    int ( a[N1] )[N2];
    int ( * p )[N2] = a;
    
    for ( size_t i = 0; i < N1; i++)
    {
        printf( "a + %zu = %p,p + %zu = %p\n",i,( void * )( a + i ),( void * )( p + i ) );
        printf( "*( a + %zu ) = %p,*(p + %zu ) = %p\n\n",( void * )*( a + i ),( void * )*( p + i ) );
    }
    
    return 0;
}

它的输出可能看起来像

a + 0 = 0x7ffda1063ab0,p + 0 = 0x7ffda1063ab0
*( a + 0 ) = 0x7ffda1063ab0,*(p + 0 ) = 0x7ffda1063ab0

a + 1 = 0x7ffda1063ac4,p + 1 = 0x7ffda1063ac4
*( a + 1 ) = 0x7ffda1063ac4,*(p + 1 ) = 0x7ffda1063ac4

a + 2 = 0x7ffda1063ad8,p + 2 = 0x7ffda1063ad8
*( a + 2 ) = 0x7ffda1063ad8,*(p + 2 ) = 0x7ffda1063ad8

注意表达式 a + 0 的值比表达式 a + 1 的值小 20(或十六进制 0x14),因为 {{1 }} 等于 sizeof( *( a + i ) ) 等于 sizeof( int[5] )

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 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-