0长度数组的使用,重点掌握的知识

2023-10-26

0长度的数组在ISO C和C++的规格说明书中是不允许的,但是GCC的C99支持的这种用法。
GCC对0长度数组的文档参考:“Arrays of Length Zero

如下代码片段,哪个更简洁更灵活,看一眼就知道了:

#include <stdlib.h>
#include <string.h>
 
typedef struct tagArray  
{
   int length;
   char contents[]; //这个成员必须是结构体的最后一个成员。
}ARRAY_S;

typedef struct tagPointer
{
    int length;
    char *contents;
}POINTER_S;
 
int main()
{
    int array_length = 10;
    ARRAY_S *pArray  = (ARRAY_S*)malloc (sizeof(ARRAY_S) + array_length);
    POINTER_S *pPointer = NULL;

    if (NULL == pArray)
    {
        return 0;
    }

    pArray->length = array_length;
    memset(pArray->contents, 'a', array_length);

    free(pArray);

    pPointer = (POINTER_S*)malloc(sizeof(POINTER_S));
    if(pPointer == NULL)
    {
        return 0;
    }
    memset(pPointer, 0, sizeof(POINTER_S));
    pPointer->length = array_length;
    pPointer->contents = (char*)malloc(array_length);
    if (pPointer->contents == NULL)
    {
        free(pPointer);
        return 0;
    }
    memset(pPointer->contents, 'a', array_length);

    free(pPointer->contents);
    free(pPointer);

    return 0;
}
第一种结构体的定义:想给一个结构体内的数据分配一个连续的内存,有两个好处:

(1)方便内存释放。
如果我们的代码提供给别人使用,你在里面做了二次内存分配,并把整个结构体返回给用户。
用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。
所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。

(2)有利于访问速度。
连续的内存有益于提高访问速度,也有益于减少内存碎片。

第二种结构体的使用:需要分配两次内存以及释放两次内存,在检查申请内存成功与否的代码量上看也明显没有第一种更简洁。

 

 

看看内存是怎么个连续的,用gdb的x命令来查看:(ARRAY_S中的那个char contents[]不占用结构体的内存,
所以ARRAY_S就只有一个int成员,4个字节,而我们还要为contents[]分配10个字节长度,所以,一共是14个字节):

 

 1 (gdb) p pArray 
 2 $1 = (ARRAY_S *) 0x804b008
 3 (gdb) p *pArray 
 4 $2 = {length = 10, contents = 0x804b00c "aaaaaaaaaa"}
 5 (gdb) p pArray ->contents 
 6 $3 = 0x804b00c "aaaaaaaaaa"
 7 (gdb) x/14b pArray 
 8 0x804b008:      10      0       0       0       97      97      97      97
 9 0x804b010:      97      97      97      97      97      97
  从上面的内存布局我们可以看到,前4个字节是 int length,后10个字节就是char contents[]。

  如果用指针的话,会变成这个样子:
10 (gdb) p pPointer 
11 $4 = (POINTER_S *) 0x804b020
12 (gdb) p *pPointer 
13 $5 = {length = 10, contents = 0x804b030 "aaaaaaaaaa"}
14 (gdb) p pPointer ->contents 
15 $6 = 0x804b030 "aaaaaaaaaa"
16 (gdb) x/16b pPointer 
17 0x804b020:      10      0       0       0       48      -80     4       8
18 0x804b028:      0       0       0       0       17      0       0       0
19 (gdb) x/10b pPointer ->contents 
20 0x804b030:      97      97      97      97      97      97      97      97
21 0x804b038:      97      97
22 (gdb) x/16x pPointer 
23 0x804b020:      0x0a    0x00    0x00    0x00    0x30    0xb0    0x04    0x08
24 0x804b028:      0x00    0x00    0x00    0x00    0x11    0x00    0x00    0x00

    第17行前四个字节是 int length,后四个字节是contents的地址。
    第23行以16进制显示,地址是: 0x30 0xb0 0x04 0x08, 即:0x0804b030。
    第20行和第21行是char* contents指向的内容。

    因此,可以看出其中的差别:数组的原地就是内容,而指针的那里保存的是内容的地址。

疑问

       为什么不使用指针来代替零长度数组:

大家在各种场合,可能常常会看到这样的字眼:数组名在作为函数参数进行参数传递时,就相当于是一个指针。在这里,我们千万别被这句话迷惑了:数组名在作为函数参数传递时,确实传递的是一个地址,但数组名绝不是指针,两者不是同一个东西。数组名用来表征一块连续内存存储空间的地址,而指针是一个变量,编译器要给它单独再分配一个内存空间,用来存放它指向的变量的地址。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

0长度数组的使用,重点掌握的知识 的相关文章

随机推荐

  • C语言:冒泡排序法:将若干字符串按字母顺序(由小到大)排序输出

    include
  • 大二上详细计划(量化到周)

    目录 前言 统筹安排 每周量化 每周进度 总体 花絮 前言 1 思来想去 决定对大二上的四个月进行一个安排 量化每周任务 具体到一本书看多少页 一套视频学多少 每个节点任务完成度 2 我们都是思想上的巨人 行动上的矮子 各种各样的欲望会阻碍
  • SpringCloud:Gateway之StripPrefix使用

    StripPrefix 过滤配置 很多时候也会有这么一种请求 用户请求路径是 api goods 而真实路径是 goods 这时候我们需要去掉 api才是真实路径 此时可以使用StripPrefix功能来实现路径的过滤操作 如下配置 ser
  • c语言时间序列预测,2.5.2 扩展案例:预测离散值时间序列

    2 5 2 扩展案例 预测离散值时间序列 假设我们观察到取值为0或1的数据 每个时刻一个值 为了了解具体应用 假设这是每天的天气数据 1代表有雨 0代表没有雨 假设已经知道最近几天是否下雨 我们希望预测明天是否会下雨 具体而言 对于某个k值
  • C++指针

    指针是一个存放内存地址的变量 通过指针 可以间接操作其它变量 指针的常用操作 int a 0 定义一个变量 int p a 定义一个指针 并指向a p 1 通过指针间接操作a 此时a 1 注意 p的类型是int 访问区域为4字节 Ps in
  • Revit二次开发--过滤对象(Revit 2014)

    1 获取元素的ID 通过UIDocument的Selection属性获取当前视图中选中的元素的ID 类型 using System using System Collections Generic using System Linq usi
  • QT - QML 遇到 module “QtQuick.Controls“ version 2.5 is not installed 的相关问题的解决策略

    问题由来 在跟着视频敲代码时 需要用到 DelayButton 这个控件 因此需要导入相关的库模块 跟着视频敲的是import QtQuick Controls 2 5 但可能由于版本较低的原因没有安装这个库模块 根据输入提示 有个 imp
  • STM32F407的CAN通信实验CAN1CAN2的设置

    CAN2的初始化参照上一篇博文就OK了 需要修改的地方 配置过滤器 CAN FilterInitStructure CAN FilterNumber 14 那为什么要修改额 查datasheet 双 CAN CAN1 主 bxCAN 用于管
  • Flex应用程序启动详解

    编写一个简单的Flex应用程序并不复杂 就算你从来没接触过Flex程序设计 照着帮助的实例步骤 不需花多长时间也能做出一个漂亮简捷的小程序出来 不过 随着对Flex程序编写的深入 会越来越觉得 其实要编写一个好的Flex应用程序并不简单 涉
  • uniapp切片-可视化设计工具(一套代码编译到7个平台iOS、Android、H5、小程序)

    uni app 是一个使用 Vue js 开发跨平台应用的前端框架 开发者编写一套代码 可编译到iOS Android H5 小程序等多个平台 一套代码编到7个平台 难以置信吗 依次扫描7个二维码 亲自体验最全面的跨平台效果 uni app
  • C++之sort()函数详解,刷题必备~

    顾名思义 sort就是用来排序的函数 它根据具体情形使用不同的排序方法 效率较高 一般来说 不推荐使用C语言中的qsort函数 原因是qsort用起来比较烦琐 涉及很多指针的操作 而且sort在实现中规避了经典快速排序中可能出现的会导致实际
  • C# 中的sealed修饰符学习

    转载原地址 http developer 51cto com art 200908 147327 htm C 语言还是比较常见的东西 这里我们主要介绍C sealed修饰符 包括介绍两个修饰符在含义上互相排斥用于方法和属性等方面 C sea
  • python爬虫网络出错怎么办_Python爬虫异常处理

    100 继续 客户端应当继续发送请求 客户端应当继续发送请求的剩余部分 或者如果请求已经完成 忽略这个响应 101 转换协议 在发送完这个响应最后的空行后 服务器将会切换到在Upgrade 消息头中定义的那些协议 只有在切换新的协议更有好处
  • linux上redis常用命令以及遇到的问题

    1 在linux上解压缩后使用make命令进行编译的时候 错误类型 zmalloc h 50 31 致命错误 jemalloc jemalloc h 没有那个文件或目录 原因是因为编译的时候Linux默认内存分配器是jemalloc 而Re
  • 添加商品到购物车 Vuex

    商品详情 购物车页面 code
  • OFDM插入导频过程详解

    ofdm符号的长度 有效数据 cp的长度 cp就是将有效数据的后半部分1 4截取并添加到有效数据的开始部分 比如一个ofdm符号的长度为4us 那么有效数据的长度为3 2us cp的长度为0 8us 子载波的间隔 1 有效数据的长度 就是有
  • Unity使用c#开发遇上的问题(十三)(unity平台下使用 Vuforia 以及 ARFoundiation 的总结,根据个人观点)

    文章目录 前言 一 Vuforia的使用感觉 二 ARfoundiation的使用感觉 总结 前言 有一段时间没有更新系列的内容 上次更新完又重新思考了一下以后进行的方向 这里就目前接触的Vuforia 和 unity 自带的AR 之前叫A
  • 自动生成根据mysql表创建hive表脚本

    bin bash source etc profile 该脚本为手动传参根据MySQL表信息创建hive表 输入参数判断逻辑 必须数据两个参数 一个是MySQL库名 第二个是表名 if eq 2 then db name 1 mysql 库
  • 浅析java垃圾回收机制

    一 什么是垃圾回收 1 垃圾回收 顾名思义 便是将已经分配出去的 但却不再使用的内存回收回来 以便能够再次分配 在 Java 虚拟机的语境下 垃圾指的是死亡的对象所占据的堆空间 垃圾回收只会负责释放那些对象占有的内存 此时对象也就被销毁 2
  • 0长度数组的使用,重点掌握的知识

    0长度的数组在ISO C和C 的规格说明书中是不允许的 但是GCC的C99支持的这种用法 GCC对0长度数组的文档参考 Arrays of Length Zero 如下代码片段 哪个更简洁更灵活 看一眼就知道了 include