C柔性数组和变长数组

变长数组

C语言在C99以前,数组的维度必须是整数常量表达式, 而C99则做了很大改进,允许数组维度为整形变量或者整形表达式(关键点运行时才能确定)。这种数组称为(variable-length array),简称VLA,中文一般称为变长数组。
例如:

int n;
scanf("%d", &n);
int array[n];

以上这种写法在C99 以前是不会通过编译的。那么VLA是怎么实现的呢?
看看下面的柔性数组或许有些启发。

柔性数组

例如要在结构体中存放一个长度不固定的字符串,可以采用下面这种方式。

#include 
#include 
#include 

typedef struct line
{
    int len;
    char *contents;
}line;

int main(int argc, char **argv)
{
    char str[] = "hello world";

    struct line *ptr = (struct line*)malloc(sizeof(line) + strlen(str) + 1);
    
    ptr->len = strlen(str);
    strcpy((char*)(ptr + 1), str);
     /*
    printf("start: %p\n\n", (char*)ptr);

    printf("(char*)(ptr+1)address: %p\n", (char*)(ptr+1));
    printf("(char*)(ptr+1): %s\n\n", (char*)(ptr+1));

    printf("&(ptr->contents): %p\n", &(ptr->contents));
    printf("ptr->contents: %s\n\n", ptr->contents);

    printf("sizeof(int): %d\n", sizeof(int));
    printf("sizeof(line): %d\n", sizeof(line));
    */
}
/*
 *注释掉的代码用于查看内存地址,方便理解,顺便可以发现内存对齐现象。
 *编译: Linux gcc.
 */

但这样处理等同于浪费掉了*contents, 且取用字符串时, 必须用(char*)(ptr+1)的方式, 那么有没有可以既可以不浪费掉*contents, 又可以直接用ptr->contents的方式取字符串呢?那么就要靠下面展示的柔性数组(零长数组)了。

#include 
#include 
#include 

typedef struct line
{
    int len;
    char contents[0];    // 修改的地方。
}line;

int main(int argc, char **argv)
{
    char str[] = "hello world";

    struct line *ptr = (struct line*)malloc(sizeof(line) + strlen(str) + 1);
    
    ptr->len = strlen(str);
    strcpy((char*)(ptr + 1), str);
  /*
    printf("start: %p\n\n", (char*)ptr);

    printf("(char*)(ptr+1)address: %p\n", (char*)(ptr+1));
    printf("(char*)(ptr+1): %s\n\n", (char*)(ptr+1));

    printf("&(ptr->contents): %p\n", &(ptr->contents));
    printf("ptr->contents: %s\n\n", ptr->contents);


    printf("sizeof(int): %d\n", sizeof(int));
    printf("sizeof(line): %d\n", sizeof(line));
  */
}

这样做的巧妙之处,数组长度为0的contents并不会占用内存空间,这个非对象符号仅仅代表一个地址而已。但C语言标准库不允许定义长度为0的数组,能否实现要靠编译器是否有扩展该功能。
所以按照柔性数组我们可以猜测一下VLA大概实现(仅仅是猜测, 我也不知道对不对):

#include 
#include 

typedef struct Array{
    int data[0];
}Array;

int main(int argc, char **argv)
{
    int n;
    scanf("%d", &n);
    Array *p = (Array*)malloc(sizeof(int) * n);
        
    ((int*)p)[0] = 10;
    ((int*)p)[1] = 20;
    ((int*)p)[2] = 30;

    printf("n=%d, %d, %d, %d\n", n, ((int*)p)[0], ((int*)p)[1], ((int*)p)[2]);
}

好吧,VLA和柔性数组大概就介绍这么多,才疏学浅,如有疏漏,望指正。

你可能感兴趣的:(C柔性数组和变长数组)