【C语言】长度为0的数组

最近在看代码的时候发现一个好玩的事情,长度为0的数组,在此记录一下。
在网上看到的这个说是只有GNU C才支持的特性,因此考虑跨平台或者可移植特点需要慎用。

话不多说,上案例才有感觉。

int a[0];
printf("size = %d\n", sizeof(a));	//打印size = 0

通过打印的信息可以查出,变量a占用的空间大小竟然是0,那么这种数组有什么用呢?

这类数组通常出现在结构体中,并在某些特定场景下使用,比如对于发消息的buffer区,消息的长度通常是不同的,这个时候就可以使用长度为0的数组了。单独声明长度为0的数组往往没有意义。

typedef struct tag_BUFFER
{
     
    int  length;
    char buf[0];
}BUFFER;

通过打印结构体的大小发现buf变量并不占用空间。

printf("BUFFER size = %d\n", sizeof(buf));	//打印BUFFER size = 4

那么如何去使用呢?其实在实际应用中往往把这个数组当成一个指针去使用,如下所示,申请内存的时候只需要申请一次就可以,释放的时候也是相同的道理。

int len = 32;
BUFFER* pBuf = NULL;

pBuf = (BUFFER*)malloc(sizeof(BUFFER) + len);
memset(pBuf, 0, sizeof(BUFFER) + len);
pBuf->length = len;

通过打印变量地址可以看到buf的地址就是首地址加上sizeof(int)的值,说明它们是一块连续的内存。长度为0的数组使用也有限制的地方,就是它只能在结构体的最后进行声明。

其实使用指针可以完成相同的操作,定义下面的结构体,

typedef struct tag_BUFFER
{
     
    int  length;
    char *buf;
}BUFFER;

存在差异的地方是,指针需要占用一定的内存空间,其次就是在分配内存的时候需要分配两次,先分配BUFFER的空间,在申请buf的空间,释放的时候也需要释放两次,并且需要注意释放顺序,与申请时相反。

对于某些编译器不支持长度为0的数组的定义,在这种情况下,只能将它定义成char buf[1],使用方法相同。

typedef struct tag_BUFFER
{
     
    int  length;
    char buf[1];
}BUFFER;

申请内存:

int len = 32;
BUFFER* pBuf = NULL;

pBuf = (BUFFER*)malloc(offsetof(BUFFER, buf) + len * sizeof(pBuf->buf[0]));
memset(pBuf, 0, sizeof(BUFFER) + len);
pBuf->length = len;

完整的代码

#include 
#include 
#include 

typedef struct tag_BUFFER
{
     
    int  length;
    char buf[0];
}BUFFER;

int main()
{
     
    int a[0];
    printf("size = %d\n", sizeof(a));

    BUFFER  buf  = {
     0};
    printf("BUFFER size = %d\n", sizeof(buf));

    int len = 32;
    BUFFER* pBuf = NULL;

    pBuf = (BUFFER*)malloc(sizeof(BUFFER) + len);
    memset(pBuf, 0, sizeof(BUFFER) + len);
    pBuf->length = len;

    printf("pBuf addr = %p, length addr = %p\tbuf addr = %p\n", pBuf, &(pBuf->length), &(pBuf->buf));

    free(pBuf);
    pBuf = NULL;
    return 0;
}

输出结果如下:

size = 0
BUFFER size = 4
pBuf addr = 0xa28010, length addr = 0xa28010    buf addr = 0xa28014

你可能感兴趣的:(C/C++知识,c语言)