我存储包含特定顺序的输入数据,因此我选择使用数组对它们进行排序:
struct Node** array = (struct Node**)malloc(sizeof(Node**) * DEFAULT_SIZE);
int i;
int size = DEFAULT_SIZE;
while(/* reading input */) {
// do something
int index = token; // token is part of an input line, which specifies the order
struct Node* node = (struct Node*)malloc(sizeof(struct Node));
*node = (struct Node){value, index};
// do something
if (index >= size) {
array = realloc(array, index + 1);
size = index + 1;
}
array[index] = node;
}
我试图循环遍历数组并在索引处存在节点时执行某些操作
int i;
for (i = 0; i < size; i++) {
if (/* node at array[i] exists */) {
// do something
}
}
如何检查节点是否存在于阵列的特定索引处? (或者在分配内存后,struct节点的“默认值”是什么?)我只知道它不是NULL
...
我应该使用calloc
并尝试if ((int)array[index] != 0)
?或者我有一个更好的数据结构可以使用?
当您使用realloc
(或malloc
)指针列表时,系统会调整大小/移动数组,在需要时复制数据,并在不更改数据的情况下保留更多空间,这样您就可以获得之前的数据。你不能依赖这些价值观。
只有calloc
做零初始,但你不能calloc
当你realloc
。
对于初学者,你应该使用calloc
:
struct Node** array = calloc(DEFAULT_SIZE,sizeof(*array));
在你的循环中,只需使用realloc
并将新内存设置为NULL
,这样就可以测试空指针
请注意,您的realloc
大小不正确,您必须乘以元素的大小。还要在重新分配后更新size
,否则将不会多次运行。
请注意棘手的memset
,它只会将未分配的数据归零,而不会更改有效的指针数据。由于指针算法,array+size
计算正确的地址大小,但size参数以字节为单位,因此你必须乘以sizeof(*array)
(元素的大小)
if (index >= size)
{
array = realloc(array, (index + 1)*sizeof(*array)); // fixed size
memset(array+size,0,(index+1-size) * sizeof(*array)); // zero the rest of elements
size = index+1; // update size
}
在旁边:
realloc
效率低下,你应该重新分配块以避免太多的系统调用/拷贝malloc
调用,无需投射malloc
的返回值,也更好地通过sizeof(*array)
而不是sizeof(Node **)
。如果array
的类型改变你的覆盖范围(也保护你免受星号类型的一次性错误)新分配的内存包含垃圾,从未初始化的内存中读取指针是一个错误。
如果使用calloc( DEFAULT_SIZE, sizeof(Node*) )
分配,则将定义数组的内容:所有位都将设置为零。在许多实现中,这是一个NULL
指针,虽然标准不保证它。从技术上讲,可能存在符合标准的编译器,如果您尝试读取所有位设置为零的指针,则会导致程序崩溃。
(只有语言律师需要担心这一点。在实践中,即使是人们提出的五十年前的大型机作为NULL
不是二进制0的机器的例子更新其C编译器将0识别为NULL
指针,因为那打破了太多代码。)
执行所需操作的安全,可移植的方法是将数组中的每个指针初始化为NULL
:
struct Node** const array = malloc(sizeof(Node**) * DEFAULT_SIZE);
// Check for out-of-memory error if you really want to.
for ( ptrdiff_t i = 0; i < DEFAULT_SIZE; ++i )
array[i] = NULL;
循环执行后,数组中的每个指针都等于NULL
,并且!
运算符为它返回1,直到它被设置为其他值。
realloc()
电话是错误的。如果你想这样做,size参数应该是元素大小的新元素数。该代码将愉快地使其成为所需大小的四分之一或八分之一。即使没有内存破坏错误,您也会发现自己经常进行重新分配,这可能需要将整个阵列复制到内存中的新位置。
对此的经典解决方案是创建一个数组页面的链接列表,但如果你要使用realloc()
,最好每次将数组大小乘以常量。
类似地,当您创建每个Node
时,如果您关心可移植性,则需要初始化其指针字段。如果你这样做,本世纪没有编译器会产生效率较低的代码。
如果您只按顺序分配节点,则可以选择创建Node
而不是Node*
的数组,并维护一个计数器,其中包含正在使用的节点数。现代桌面操作系统只会在进程写入时映射数组的物理内存页面,因此简单地分配而不是初始化大型动态数组不会浪费大多数环境中的实际资源。
另一个可能是良性的错误:数组的元素有struct Node*
类型,但是你为每个元素分配sizeof(Node**)
而不是sizeof(Node*)
字节。但是,编译器不会对此进行类型检查,并且我不知道任何编译器,这两种对象指针的大小可能不同。
你可能需要这样的东西
unsigned long i;
for (i = 0; i < size; i++) {
if (array[i]->someValidationMember==yourIntValue) {
// do something
}
}
编辑。要分配的内存必须为空。或者如果删除了一个项目,只需将Node成员更改为零或任何您选择的。