结构体中长度为0的字符数组

在C语言的结构体中,有一种特殊用法,在结构体的末尾放置一个长度为0的字符数组,结构体倒数第二个位置放置一个整型变量len。其典型样例如下:

typedef struct dynamic_value {
  int flag;
  int len;
  char val[0];
}s_flv;

本文针对其特征,用法及适用场合予以简单介绍。

特征

  • 最后的字符数组val长度为0,不占用额外的内存空间
  • 倒数第二个元素为一整型变量,用于存储字符数组的真实长度
  • val实际指向的是结构体s_flv之后的内存空间
  • 字符数组的大小可以在定义结构体变量时动态指定s_flv.len
  • 结构体元素个数不限,样例为典型模式,其中的flag作为标签用以标识不同的数据

用法

  • s_flv格式写入数据到文件
#include <stdio.h>

static void write_flv(FILE *fp, int flag, char *val)
{
    int len = 0;
    if(val == NULL)
        val = "";
    else
        len = strlen(val);

    fwrite(&flag, sizeof(flag), 1, fp); // 写入标识
    fwrite(&len, sizeof(len), 1, fp);   // 写入字符数组长度
    fwrite(val, len, 1, fp);    // 写入长度为len的字符串
}
  • 读取文件
#include <stdio.h>

static int read_flv(char *file, char *val)
{
    char buf[32];   // 假定字符数组长度小等于32
    char *p = buf;

    FILE *fp = fopen(file, "r");
    if(!fp)
        return -1;

    if(fread(buf, 2*sizeof(int), 1, fp) <= 0)   // 读取前两个整型数据,获取字符数组长度
        return -1;

    s_flv *flv = (s_flv *)p;        // 定义s_flv结构体,存储数据
    fread(val, flv->len, 1, fp);    // 读取字符数组
    flose(fp);
    return 0;
}
  • 说明
    • 每执行一次freadfwrite函数,文件指针就往后偏移相应的读取长度或写入长度
    • read_flv定义flv时,从buf中可以获取到数组长度,然后使用fread读取相应长度的数据即可取出字符数组的内容。
    • 使用以上方法生成的文件内容是二进制文件,许多字符是不可打印字符,所以使用cat指令无法正常显示文件内容

上面描述的方法是将s_flv类型的数据存入文件,但如果不想存入文件,那么该如何为其分配内存呢,下面来看一下:

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

// 定义s_flv指针变量
int size = 10;
s_flv *flv = (s_flv *)malloc(sizeof(s_flv) + size);
flv->len = size;
flv->val = flv + sizeof(s_flv);

// 释放指针
free(flv);

适用场合

  • json文件的读写
  • 不定长度字符串的读写

扩展阅读