Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何访问结构数组_C_Struct_Malloc - Fatal编程技术网

C 如何访问结构数组

C 如何访问结构数组,c,struct,malloc,C,Struct,Malloc,我对如何访问结构数组感到困惑 简单案例: 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;

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

简单案例:

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;
}
typedef结构节点
{
整数;
结构节点*左;
结构节点*右;
}节点;
node*noderray=malloc(511*sizeof(node));
对于(int i=0;i<511;i++)
{
noderRay[i]->number=i;
}

然而,noderray[i].number=i似乎确实有效。有人能解释一下发生了什么,以及node*noderray=malloc(511*sizeof(node))之间的区别吗
节点(*noderray)=malloc(511*sizeof(节点))

问题可能是由对齐引起的:

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

sizeof(type)
只返回一个最小存储大小(额外分配的填充不应可访问,即使在运行时或编译器未对此进行检查)

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

替换:

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

作者:

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

现在您的代码通常是安全的,实际分配的大小将包括底层架构所需的额外填充

否则,您的代码是不可移植的

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

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

当使用简单类型时,您看不到区别(您不关心它们的对齐方式,也不关心它们被孤立地分配到哪里,在堆栈上或使用它们的结构中可能会分配额外的填充,这是不可访问的,即使在物理寄存器中分配存储时不需要填充;但即使使用“自动”或“寄存器”分配时,编译器仍然可以为它分配堆栈上的空间,作为后备存储,当需要其他程序或执行外部函数调用时,可以用来保存寄存器,或者在C++中调用方法,而不登记函数体。 请参阅C++11中的
alignof
alignas
声明器的文档。有许多关于它们的资源;例如:

请参阅
calloc()的文档

(不要被Linux中使用的简化32位或64位内存模型弄糊涂了;即使是Linux现在也使用更精确的内存模型,考虑到对齐问题,以及可访问性和性能问题,有时底层平台出于良好的安全原因强制执行,以减少存在的攻击表面。)在单一/统一的“平面”中适用于一切的内存模型:分段式体系结构重新出现在计算行业中,C/C++编译器必须适应:C++11回答了这个问题,否则将需要在编译的代码中使用成本更高或效率更低的解决方案,严重限制了一些优化,如缓存管理、TLB存储的效率、分页和存储虚拟化内存、用户/进程/线程的强制安全作用域等)

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

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


同样,您的
noderray[i]
返回对节点对象的引用,而不是指针,因此
noderray[i]>任何内容都是无效的:您需要在第一个代码段中用

替换
,以下内容都是等效的:

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 = 5;          // preferred
nodeArray[0].number = 5;
(*nodeArray).number = 5;
(nodeArray + i)->number = i;
nodeArray[i].number = i;        // preferred
(*(nodeArray + i)).number = i;

因此,如您所见,有三种不同的语法可供选择,它们的作用都是相同的。在处理指向结构的单个实例的指针时,首选箭头语法(
noderray->number
)。使用点符号(
noderray[i].number
)的数组索引当处理指向结构数组的指针时,最好使用。明智的程序员避免使用第三种语法(取消指针和点符号的引用)。

当您分配这样的数组时

node* nodeArray = malloc(511*sizeof(node));
noderray
是一个指针,获取指向单个结构节点的指针只需添加一个整数: