灵活数组成员的非静态初始化?

Veg*_*gas 3 c

#include <stdio.h>
#include <limits.h>

typedef struct item {
    int low; int high; char label[16];
} Item;

typedef struct item_coll {
    size_t length; Item *items[];
} ItemColl;

char *find_first_in_range(ItemColl *ic, int rlow, int rhigh) {
    for (size_t i = 0; i < ic->length; i++)
        if (ic->items[i]->low >= rlow && ic->items[i]->high <= rhigh)
            return &ic->items[i]->label[0];
    return NULL;
}

int main() {
    struct item fruits[] = {
        {10, 20, "Apple"},
        {12, 14, "Pear"},
        {8, 12, "Banana"},
        {2, 4, "Grape"},
        {15, 35, "Watermelon"}
    };

    struct item_coll basket = {5, fruits};

    printf("%s", find_first_in_range(&basket, 21, 22));

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这给了我app.c:28:32: error: non-static initialization of a flexible array member struct item_coll basket = {5, fruits};

并且错误指向fruits.

这是什么意思?我觉得不错。

Dav*_*ica 7

如果这是一项考试,并且您必须使用灵活数组成员,那么正如我在评论中指出的以及 @rici 在他的回答中解释的那样,FAM 的目的是提供给定的占位符,type然后允许您分配结构本身的存储加上单个分配中某些数量的 FAM 类型的存储。这样做的优点是单一分配/单一释放,而不是对结构进行单独分配,然后分配一些所需类型。

(在 FAM 之前,存在所谓的struct hack1 ,其中使用大小的数组来代替其位置,以达到几乎相同的目的)

type对于您如何处理和分配 FAM 至关重要。在您的情况下,您的 FAM 是item *items[];(指向类型的指针数组item-Item在您的代码中),因此您分配结构体,然后X分配指向item.

要初始化 的每个成员,您必须为类型的结构items分配一个有效地址item(或者您可以单独分配,复制到新块,然后将该块的起始地址分配给 中的指针items)在您的情况下,您有一个名为 的结构体数组 。要分配给,您必须将每个结构的地址分配给中的每个元素(请记住,您有指针存储,而不是结构存储- 并且您必须确保在使用期间保留在范围内)itemfruitsitemsitemsitemfruitsbasket

将这些部分放在一起,您可以执行类似于以下操作的操作:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

typedef struct {
    int low, high;
    char label[16];
} item;

typedef struct {
    size_t length;
    item *items[];
} item_coll;

char *find_first_in_range(item_coll *ic, int rlow, int rhigh) 
{
    for (size_t i = 0; i < ic->length; i++)
        if (ic->items[i]->low >= rlow && ic->items[i]->high <= rhigh)
            return ic->items[i]->label;
    return NULL;
}

int main() {

    item fruits[] = {
        {10, 20, "Apple"},
        {12, 14, "Pear"},
        { 8, 12, "Banana"},
        { 2,  4, "Grape"},
        {15, 35, "Watermelon"}
    };
    size_t nfruits = sizeof fruits/sizeof *fruits;  /* avoid magic-numbers */
    /* allocate storage for basket + nfruits pointers */
    item_coll *basket = malloc (sizeof *basket + 
                                nfruits * sizeof *basket->items);
    if (!basket) {  /* validate allocation succeeded */
        perror ("malloc-basket+5_item_coll");
        return 1;
    }
    basket->length = nfruits;   /* assign length */

    for (size_t i = 0; i < nfruits; i++)  /* assign addresses to structs */
        basket->items[i] = &fruits[i];

    char *label = find_first_in_range (basket, 12, 15);  /* save return */
    if (label)  /* validate not NULL before printing */
        printf ("%s\n", label);

    free (basket);  /* don't forget to free the memory you allocate */

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

请注意,我只是使用了 typedef 并删除了结构标签本身 - 这取决于您。此外,您应该在打印之前验证find_first_in_rangeis not 的返回NULL。)

使用/输出示例

另请注意,我已将high/low范围括起来

$ ./bin/fam_initialization
Pear
Run Code Online (Sandbox Code Playgroud)

内存使用/错误检查

在您编写的动态分配内存的任何代码中,对于分配的任何内存块,您有 2 个责任:(1) 始终保留指向内存块起始地址的指针,(2)当内存块不可用时可以将其释放。更需要。

您必须使用内存错误检查程序来确保您不会尝试访问内存或在分配的块的范围之外进行写入,尝试读取未初始化的值或将条件跳转建立在未初始化的值上,最后确认释放所有已分配的内存。

对于Linux来说valgrind是正常的选择。每个平台都有类似的内存检查器。它们使用起来都很简单,只需通过它运行您的程序即可。

$ valgrind ./bin/fam_initialization
==6887== Memcheck, a memory error detector
==6887== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6887== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==6887== Command: ./bin/fam_initialization
==6887==
Pear
==6887==
==6887== HEAP SUMMARY:
==6887==     in use at exit: 0 bytes in 0 blocks
==6887==   total heap usage: 1 allocs, 1 frees, 48 bytes allocated
==6887==
==6887== All heap blocks were freed -- no leaks are possible
==6887==
==6887== For counts of detected and suppressed errors, rerun with: -v
==6887== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Run Code Online (Sandbox Code Playgroud)

始终确认您已释放已分配的所有内存并且不存在内存错误。

检查一下,如果您还有其他问题,请告诉我。