长度为0的数组的使用

2023-03-27 18:16:45

1:背景

在阅读别人的代码的时候发现一种特别的结构体成员,一个长度为0的数组,类似于arr[0]。当时并不知为什么这样写。查阅一些资料才知道这个的妙用。

2:使用场所

长度为0的数据,目前好像只有GNU的C才支持。标准c和c++中是不允许。如果也想用的话,要使用长度为1的数组,来代替。

GNU的C不对越界的数组报错,会直接让你使用越界后的地址。数组越界后,会自动接着前面那块内存往后写,这样带来的将会是一系列安全问题。因为界外的内存不确定是否已经存放了东西,如果不凑巧存放着比较重要的数据,那么数组越界后将会把这块内存上的重要数据替换掉,后果可想而知。所以你要确保越界的地址空间是你可以控制的。例如使用malloc多分配一些空间,这段多分配的空间就是可以控制的。

3:出现的原因

通常我们使用结构体时,也需要在结构体中定义一些指针来指向别的空间。这样的话,你需要先为外层的结构体分配空间然后再为内部的指针分配空间。释放的时候先释放内部,再释放外部。
如果长度为0的数组的放在结构体的尾部,然后申请大于该结构体的空间
像这样

struct s{
    char c;
    float f;
    char arr[0];
};
struct s *t = (struct s*)malloc(sizeof(struct s) + 10);

那么就产生一种很有趣的情况,就是在结构体成员arr处向后的10个字节,也可以被使用了。起始地址就是arr。
这样的话,只需要分配一次就可以有多余的空间可以被使用,如果释放的只需要释放t就可以把所有的申请空间全部释放。

4:示例


/*************************************************************************
    > File Name: null_arr.c
    > Author: kayshi
    > Mail: kayshi2019@qq.com
    > Created Time: Fri 27 Nov 2020 08:28:48 AM CST
 ************************************************************************/

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

struct s{
    char c;
    float f;
    char arr[0];
};


int main()
{
    struct s *t = (struct s*)malloc(sizeof(struct s) + 10);
    if(!t)
        exit(1);
    t->c = 5;
    t->f = 3.14;
    strcpy(t->arr, "hello");

    printf("%d, %f, %s \n", t->c, t->f, t->arr);
}

结果

kayshi@ubuntu:~/code/Test$ ./a.out 
5, 3.140000, hello 
kayshi@ubuntu:~/code/Test$ 

结构体最后使用0或1的长度数组的原因,主要是为了方便的管理内存缓冲区,如果你直接使用指针而不使用数组,那么,你在分配内存缓冲区时,就必须分配结构体一次,然后再分配结构体内的指针一次,(而此时分配的内存已经与结构体的内存不连续了,所以要分别管理即申请和释放)而如果使用数组,那么只需要一次就可以全部分配出来,反过来,释放时也是一样,使用数组,一次释放,使用指针,得先释放结构体内的指针,再释放结构体。还不能颠倒次序。

其实就是分配一段连续的的内存,减少内存的碎片化

5:优点

  1. 不需要初始化,数组名直接就是所在的偏移 。
  2. 不占任何空间,指针需要占用int长度空间,空数组不占任何空间。
  3. 分配的内存连续,管理方便。
  4. 小内存的管理是非常困难的,如果用指针,这个buffer的struct部分就是小内存了, 在系统内存在多了势必严重影响内存管理的性能。要是用空数组把struct和实际数据缓冲区一次分配大块问题,就没有这个问题,解决了小内存碎片问题提高了性能。
  • 作者:kayshi2018
  • 原文链接:https://blog.csdn.net/weixin_36209467/article/details/110219874
    更新时间:2023-03-27 18:16:45