您如何访问结构数组

如何解决您如何访问结构数组

我对如何访问结构数组感到困惑。

简单情况:

typedef struct node
{
    int number;
    struct node *left;
    struct node *right;
} node;

node *nodeArray = malloc(sizeof(node));    
nodeArray->number = 5;

所以,这一切都说得通。但是以下操作无效:

typedef struct node
{
    int number;
    struct node *left;
    struct node *right;
} node;

node *nodeArray = malloc(511 * sizeof(node));
for(int i = 0; i < 511; i++)
{
    nodeArray[i]->number = i;
}

但是,nodeArray [i] .number = i确实可以工作,有人可以解释发生了什么, node *nodeArray = malloc(511 * sizeof(node)); node (*nodeArray) = malloc(511 * sizeof(node));之间有什么区别

解决方法

在第一个代码段中,以下各项均等效:

nodeArray->number = 5;          // preferred
nodeArray[0].number = 5;
(*nodeArray).number = 5;

在第二个片段中,以下各项均等效:

(nodeArray + i)->number = i;
nodeArray[i].number = i;        // preferred
(*(nodeArray + i)).number = i;

因此,如您所见,可以选择三种不同的语法来完成相同的工作。处理指向结构的单个实例的指针时,首选箭头语法(nodeArray->number)。当处理指向结构数组的指针时,首选使用点符号(nodeArray[i].number)进行数组索引。明智的程序员避免使用第三种语法(取消引用指针和点符号)。

,

分配这样的数组时

node* nodeArray = malloc(511*sizeof(node));

nodeArray是一个指针,您只需添加一个整数即可获得指向单个结构节点的指针:

nodeArray + 1将给出指向第二个节点的指针

nodeArray + 1可以写为&nodeArray[1]

所以要取消引用指针

*(nodeArray + 1).number或输入nodeArray[1].number

,

可能是对齐问题引起的:

您的节点结构包含一个整数和两个指针,其最小存储大小可以为12个字节(在大多数32位体系结构上)或24个字节(64位体系结构),但是对齐限制为该架构可能会强制使用另一个 maximum 存储大小(带有额外的填充,也需要分配该填充)来对齐每个节点。

sizeof(type)只会返回一个 minimum 的存储大小(即使在运行时或编译器未检查该额外分配的填充,也不应访问)。

解决方案:使用calloc(),它还将考虑数组中每个项目的对齐约束!

替换:

node *nodeArray = malloc(511 * sizeof(node));

作者:

node *nodeArray = calloc(511,sizeof(node));

现在您的代码通常是安全的,实际分配的大小将包括基础架构所需的必要附加填充。

否则,您的代码将无法移植。

请注意,某些C / C ++编译器还提供了alignof(type)来获取数据类型的正确对齐方式(应该在C / C ++库中用于实现void *calloc(size_t nitems,size_t size))。

您上面的示例代码可能会遭受缓冲区溢出的困扰,因为在循环中写入项目之前,您没有为数组分配足够的空间。

使用简单类型时,您看不到区别(您不关心它们的对齐方式或它们在何处被单独分配,可能会在堆栈上或使用它们的结构中分配额外的填充,这是无法访问的,即使在物理寄存器中分配其存储空间时也无需填充;但即使使用“自动”或“寄存器”分配,编译器仍可以为其在堆栈上分配空间,作为可用于保存的后备存储在需要其他东西时或在执行外部函数调用或C ++中的方法调用且函数主体未内联之前需要注册的寄存器。

请参阅C ++ 11中alignofalignas声明符的文档。关于它们有很多资源。例如:

https://en.cppreference.com/w/cpp/language/alignas

另请参阅calloc()

的文档

(不要被Linux中使用的简化的32位或64位内存模型所迷惑;甚至Linux现在也使用更精确的内存模型,并考虑到对齐问题以及可访问性和性能问题,有时出于良好的安全性考虑,由底层平台强制执行此操作是为了减少针对所有事物的单一/统一“平面”内存模型中存在的攻击面:分段式体系结构重新出现在计算行业中,C / C ++编译器必须适应:C ++ 11回答了这个问题,否则将需要在编译后的代码中使用更昂贵或效率较低的解决方案,从而严重限制了某些优化,例如缓存管理,TLB存储效率,分页和虚拟化内存,针对用户/进程/线程的强制安全范围等等)。

请记住,每个数据类型都有其自己的大小和对齐方式,并且它们是独立的。假设为数组中的数据类型分配单个“大小”是错误的(以及在分配的数组的最后一项之后,额外的填充可能未分配,并且对填充区域的读/写访问可能被编译器或在运行时限制/执行。

现在还要考虑位域的情况(数据类型声明为具有额外精度/大小参数的结构的成员):它们的sizeof()并不是真正的最小值,因为它们可以更紧密地打包(包括布尔数组:sizeof( )一旦将数据类型提升为整数,就返回该数据类型的最小大小,因此当可能通过额外的填充或符号位扩展将其放大时;通常,编译器通过使用位掩码,移位或移位来强制对填充位进行这些无效访问旋转;但是处理器可能会提供更方便的指令来处理内存中甚至寄存器中一个字单元内的位,以使您的位域不会溢出,也不会因为对其值进行算术运算而修改其他周围的位域或填充位)

同样,您的nodeArray[i]返回对节点对象的引用,而不是指针,因此nodeArray[i]->anything无效:您需要替换->中的.

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