繁体   English   中英

C中分配的结构指针的“默认值”

[英]“default value” of allocated struct pointer in C

我正在存储包含特定顺序的输入数据,因此我选择使用数组对它们进行排序:

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
    }
}

如何检查节点在数组的特定索引处是否存在? (或者分配内存后结构节点的“默认值”是什么?)我只知道它不是NULL ...

我应该使用calloc并尝试if ((int)array[index] != 0)吗? 还是我可以使用更好的数据结构?

当您重新realloc (或malloc )指针列表时,系统会调整/移动数组的大小,在需要时复制数据,并在不更改数据的情况下保留更多空间,因此您可以得到之前的内容。 您不能依赖这些值。

只有calloc会执行零初始化,但是在realloc时不能calloc

对于初学者,您可能应该使用calloc

struct Node** array = calloc(DEFAULT_SIZE,sizeof(*array));

在循环中,只需使用realloc并将新内存设置为NULL以便可以测试空指针

请注意,您的重新realloc大小不正确,您必须乘以元素的大小。 还要在重新分配后更新size ,否则将无法正常工作。

请注意棘手的memset ,该内存集仅将未分配的数据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每个元素是无效的,你应该块realloc的,以避免过多的系统调用/份
  • 我已经简化了malloc调用,无需投的返回值malloc ,同时也更好的传递sizeof(*array)来代替sizeof(Node **) 万一array的类型发生变化,您将得到覆盖(也可以保护您免受加星标类型的一次性错误)

新分配的内存包含垃圾,从未初始化的内存读取指针是一个错误。

如果使用calloc( DEFAULT_SIZE, sizeof(Node*) )分配calloc( DEFAULT_SIZE, sizeof(Node*) )则将定义数组的内容:所有位都将设置为零。 在许多实现中,这是一个NULL指针,尽管标准对此不作保证。 从技术上讲,如果您尝试读取所有位都设置为0的指针,则可能会有符合标准的编译器使程序崩溃。

(不过,只有语言律师才需要担心这一点。实际上,即使是五十岁的大型机人们也提出了以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成员更改为零或您选择的任何一个即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM