C数组/指针语义:如何使结构中的数组具有相应指针的属性/语义?

C数组/指针语义:如何使结构中的数组具有相应指针的属性/语义?,c,arrays,pointers,c99,semantics,C,Arrays,Pointers,C99,Semantics,考虑以下代码: void f_01( int a, char** flags ) { printf("flags %p\n", flags); if ( ! flags ) { return; // early exit } //some code } struct s01 { int a; char** flags1; /* NULL = not used */ char* flags[

考虑以下代码:

void f_01( int a, char** flags )
{
    printf("flags %p\n", flags);
    if ( ! flags ) 
    {
        return; // early exit
    }
    //some code
}

struct s01
{
    int     a;
    char**  flags1;     /* NULL = not used  */
    char*   flags[];    /* NULL = not used  */
} s_01 = { 13 };

int main()
{
    struct s01* s = &s_01;
    f_01( 1, NULL );
    f_01( 2, s->flags1 );//for demonstration purpose
    f_01( 3, s->flags ); //s->flags is expected to be NULL, but instead
                         //it evaluates to address of s->flags (i.e. &s->flags)
    return 0;
}
实际产量:

f_01 1 (nil)
f_01 2 (nil)
f_01 3 0x601038
预期产出:

f_01 1 (nil)
f_01 2 (nil)
f_01 3 (nil)
问题:如何使示例中的数组结构成员标志具有本示例中对应指针字符**的属性/语义,即默认初始化为NULL


这样做的目的是:能够在本例中的API实现f_01中使用相同的逻辑,并为空指针和空数组使用char**参数。也就是说,在API中没有额外的if*标志检查,因为如果标志!=如果为NULL,则它是非空数组。这是合乎逻辑的,对吗?那么为什么需要添加额外的if*处理空数组的标志检查?在C中,空数组是否可以计算为NULL指针?

结构没有将标志初始化为NULL的原因是最后一个标志是灵活的数组成员,而不是指针。结构是一种为所有要放入其中的东西分配足够空间的方法。因此,当结构具有int a;,字符**flags1;,字符*标志[];。它需要分配至少为SizeOfa(可能为16位)、sizeofchar**可能为32位和sizeofchar*[]的内存块。在这种特殊情况下,它是未知的。因为我们还不知道指针数组的大小,它会将其视为零位,当您计算出所需的大小时,需要为数组的大小分配足够的额外位。见§6.7.2.1 18-21

因此,在本例中,它将char*指针初始化为NULL,因为没有给它一个值,并且假设您需要一个大小为零的char*数组,因为没有给它一个大小值。在您的示例0x601038中,此数组仅从结构的末尾开始。因此,当你将数组传递到f_01中时,你给它零数组的起始位置


我知道你可能不想听这个,但我能想到的唯一解决办法是替换char*flags[];带有字符**标志。也许你可以制作char*flags[];更改为int-sizeOfFlags;和char*flagData[];然后只需将sizeOfFlags放入f_01。因为如果sizeOfFlags==0,则NULL==0,因此当大小为零时,它仍将为您提供NULL。但是,这样做肯定是错误的。

数组不能为NULL。这样做的目的是什么?我相信有更方便的方法来实现你的目标;据我所知,C语言中没有这样的东西。它是一个灵活的数组成员;你熟悉这些工作原理吗?它们只有在动态分配结构时才有意义。当您静态地分配它时(如示例中所示),它的行为类似于长度为1的数组,其元素可能无法访问。但是它肯定有一个地址并且不是空的。我不明白为什么你描述的行为会有用,而且在任何情况下我都很确定没有办法得到它。但是请注意,这也意味着如果你添加if*在f_01函数中使用flags,那么当您在s->flags上调用它时,您正在调用未定义的行为。