美文网首页
C柔性数组和变长数组

C柔性数组和变长数组

作者: ffusheng | 来源:发表于2017-05-13 01:17 被阅读0次

    变长数组

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

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

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

    柔性数组

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

    #include <stdio.h>
    #include <malloc.h>
    #include <string.h>
    
    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 <stdio.h>
    #include <malloc.h>
    #include <string.h>
    
    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 <stdio.h>
    #include <malloc.h>
    
    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柔性数组和变长数组

          本文链接:https://www.haomeiwen.com/subject/hqptxxtx.html