C语言中长度为0的数组详解

目录
  • 概述
  • 使用方式
  • 总结

概述

长度为0的数组在标准c和c++中是不合法的,但是在gcc中是可行的。

长度为0数组它的最典型的用法就是位于结构体中的最后一项。

使用方式

如下面的例子,分别使用长度为0的数组和指针声明结构体,实现可变长度的数组功能:

#include <stdio.h>
#include <stdlib.h>
struct test1
{
    int a;
    int b[0];
};
struct test2
{
    int a;
    int *b;
};
struct test3
{
    int a;
    int reserved;//占位符,64位系统中保证结构体字节对齐,test2中是由编译器对齐的,所以两个结构体占用空间相同
    int *b;
};
int main()
{
    struct test1 *var1;
    struct test2 *var2;
    int iLength = 10;
    int i;
    printf("the length of struct test1:%d\n",sizeof(struct test1));
    printf("the length of struct test2:%d\n",sizeof(struct test2));
    printf("the length of struct test3:%d\n",sizeof(struct test3));
    var1=(struct test1*)malloc(sizeof(struct test1) + sizeof(int) * iLength);
    var1->a=iLength;
    for(i=0; i < var1->a; i++)
    {
        var1->b[i]=i;
        printf("var1->b[%d]=%d\t", i, var1->b[i]);
    }
    printf("\n");
    printf("p var1 = %p\n", var1);
    printf("p var1->a %p\n", &var1->a);
    printf("var1->b %p\n", var1->b);
    printf("p var1->b %p\n", &var1->b);
    printf("p var1->b[0] %p\n", &var1->b[0]);
    printf("p var1->b[1] %p\n", &var1->b[1]);
    printf("\n\n");
    var2=(struct test2*)malloc(sizeof(struct test2));
    var2->a=iLength;
    var2->b=(int *)malloc(sizeof(int) * iLength);
    for(i=0; i < var2->a; i++)
    {
        var2->b[i]=i;
        printf("var2->b[%d]=%d\t", i, var2->b[i]);
    }
    printf("\n");
    printf("p var2 = %p\n", var2);
    printf("p var2->a %p\n", &var2->a);
    printf("var2->b %p\n", var2->b);
    printf("p var2->b %p\n", &var2->b);
    printf("p var2->b[0] %p\n", &var2->b[0]);
    printf("p var2->b[1] %p\n", &var2->b[1]);
    free(var1);
    free(var2->b);
    free(var2);
    return 0;
}

64位linux系统中运行结果

the length of struct test1:4
the length of struct test2:16
the length of struct test3:16
var1->b[0]=0    var1->b[1]=1    var1->b[2]=2    var1->b[3]=3    var1->b[4]=4    var1->b[5]=5    var1->b[6]=6    var1->b[7]=7    var1->b[8]=8    var1->b[9]=9
p var1 = 0x55eb1a7d7670
p var1->a 0x55eb1a7d7670
var1->b 0x55eb1a7d7674
p var1->b 0x55eb1a7d7674
p var1->b[0] 0x55eb1a7d7674
p var1->b[1] 0x55eb1a7d7678
var2->b[0]=0    var2->b[1]=1    var2->b[2]=2    var2->b[3]=3    var2->b[4]=4    var2->b[5]=5    var2->b[6]=6    var2->b[7]=7    var2->b[8]=8    var2->b[9]=9
p var2 = 0x55eb1a7d76b0
p var2->a 0x55eb1a7d76b0
var2->b 0x55eb1a7d76d0
p var2->b 0x55eb1a7d76b8
p var2->b[0] 0x55eb1a7d76d0
p var2->b[1] 0x55eb1a7d76d4

使用长度为0的数组可以比指针更方便地进行内存的管理。

结构体test1在分配内存时,则是采用一次分配的原则,一次性将所需的内存全部分配给它,释放也是一次释放。数组和结构体的内存是连续的。

结构体test2在分配内存时,需采用两步:首先,需为结构体分配一块内存空间;其次再为结构体中的成员变量分配内存空间。这样两次分配的内存是不连续的,需要分别对其进行管理。当使用长度为0的数组时,则是采用一次分配的原则,一次性将所需的内存全部分配给它。相反,释放时也是一样的。

总结

长度为0的数组并不占有内存空间,而指针方式需要占用内存空间。

对于长度为0的数组,在申请内存空间时,采用一次性分配的原则进行;对于包含指针的结构体,才申请空间时需分别进行,释放时也需分别释放。

对于长度为0的数组元素的访问可正常采用数组方式进行。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C语言中的初阶指针详解

    目录 1.指针是什么 2.指针和指针类型 3.野指针 3.1野指针成因 3.2如何规避野指针 4.指针的运算 4.1指针±整数 4.2指针-指针 4.3指针的关系运算 5.指针和数组 6.二级指针 7.指针数组 ​ 总结 1.指针是什么 ​ 初学者都有一个疑问,那就是指针是什么?简单的说,就是通过它能找到以它为地址的内存单元. 地址指向了一个确定的内存空间,所以地址形象的被称为指针. int main() { int a = 10; int* pa = &a; return 0; } //pa是

  • C语言编程之初识数组线性查找和二分查找

    目录 线性查找 二分查找 先来了解一下什么是查找, 额,好吧,这没什么可了解的, 就是查找数组中的某个元素的位置或是否存在. 就这,没了.直接了解查找算法吧. 线性查找 线性查找与二分查找有些差别. 数组内元素可以是混乱无序的,即没有按顺序储存.这方法很简单,就是从首元素开始,依此向后查找,比较.仅此而已.运用循环,依次对比. 看代码吧. #include <stdio.h> int main(void) { int arr[] = { 5,4,6,8,7,9,10,2,3,1 }; int

  • C语言动态数组详解

    目录 内存分配函数malloc calloc realloc free 内存操作函数 memset memcpy memmove 二维动态数组的建立和释放 总结 内存分配函数malloc calloc realloc free 堆内存分配函数 说明 void * malloc(int n) 形参n为要求分配的字节数.需要注意的是,malloc函数分配得到的内存空间是未初始化的.必须使用memset函数来初始化. calloc(10, sizeof(char)); 两个参数:单元数,单元的size

  • C语言指针必备基础全面覆盖

    目录 前言 一.指针是什么? 1.数据在内存中的存储 2.一个小的单元到底是多大? 二.指针变量 1.什么是指针变量 2.指针类型 3.指针类型的作用 三.野指针 1.什么是野指针 2.野指针成因 2.1. 指针未初始化 2.2指针越界访问 2.3指针指向的空间释放 3.如何规避野指针 四.指针运算 1.指针±整数 2.指针-指针 五.指针和数组 1.数组元素的指针 2.通过指针引用数组元素 六.二级指针 七.指针数组 最后 前言 指针是C语言中的一个重要概念.正确而灵活的运用指针,可以使程序间

  • C语言小知识之为什么要使用指针详析

    刚开始学习C语言的时候,感觉最难理解的就是指针,什么指针变量,变量指针,指向指针的变量,指向变量的指针?一堆概念,搞得人云里雾里的,今天不讨论这些概念的问题,从最底层来分析C语言中为什么要使用指针,指针存在的意义又是什么呢? 首先从一个简单的例子来看,写一段代码来交换x.y的值. void main( void ) { u8 x = 10, y = 20; u8 temp; __asm( "sim" ); //禁止中断 SysClkInit(); delay_init( 16 ); L

  • C语言指针基础详解

    目录 1.1:概述 1.1.1:内存 1.1.2:内存 1.1.3:指针和指针变量 1.2:指针基础知识 1.2.1:指针变量的定义和使用 1.2.2:通过指针间接修改变量的值 1.2.3:指针的大小 1.2.4:空指针与野指针 1.2.4:万能指针 1.3:指针与数组 1.3.1:数组名 1.3.2:指针操作数组 1.3.3:指针的加减运算 1.4:指针基础小结 1.5:总结 1.1:概述 1.1.1:内存 内存含义: 储存器:用来存储程序和数据,辅助CPU进行运算处理的重要组成部分. 内存:

  • C语言中长度为0的数组详解

    目录 概述 使用方式 总结 概述 长度为0的数组在标准c和c++中是不合法的,但是在gcc中是可行的. 长度为0数组它的最典型的用法就是位于结构体中的最后一项. 使用方式 如下面的例子,分别使用长度为0的数组和指针声明结构体,实现可变长度的数组功能: #include <stdio.h> #include <stdlib.h> struct test1 { int a; int b[0]; }; struct test2 { int a; int *b; }; struct tes

  • C语言变长数组 struct中char data[0]的用法详解

    今天在看一段代码时出现了用结构体实现变长数组的写法,一开始因为忘记了这种技术,所以老觉得作者的源码有误,最后经过我深思之后,终于想起以前看过的用struct实现变长数组的技术.下面是我在网上找到的一篇讲解很清楚的文章. 在实际的编程中,我们经常需要使用变长数组,但是C语言并不支持变长的数组.此时,我们可以使用结构体的方法实现C语言变长数组. struct MyData { int nLen; char data[0];}; 在结构中,data是一个数组名:但该数组没有元素:该数组的真实地址紧随结

  • Go语言中函数可变参数(Variadic Parameter)详解

    目录 基本语法 示例一:函数中获取可变参数 示例二:将切片传给可变参数 示例三:多参数 基本语法 在Python中,在函数参数不确定数量的情况下,可以使用如下方式动态在函数内获取参数,args实质上是一个list,而kwargs是一个dict def myFun(*args, **kwargs): 在Go语言中,也有类似的实现方式,只不过Go中只能实现类似*args的数组方式,而无法实现**kwargs的方式.实现这种方式,其实也是利用数组的三个点表达方式,我们这里来回忆一下. 关于三个点(…)

  • C语言中文件常见操作的示例详解

    目录 文件打开和关闭 文件写入 文件读取 fseek函数 ftell函数 Demo示例 解决读取乱码 FILE为C语言提供的文件类型,它是一个结构体类型,用于存放文件的相关信息.文件打开成功时,对它作了内存分配和初始化. 每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节. 一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便. 文件打开和关闭 C语言的安全文件打开函数为_wfopen_s和_fopen_s

  • Go语言中的字符串处理方法示例详解

    1 概述 字符串,string,一串固定长度的字符连接起来的字符集合.Go语言的字符串是使用UTF-8编码的.UTF-8是Unicode的实现方式之一. Go语言原生支持字符串.使用双引号("")或反引号(``)定义. 双引号:"", 用于单行字符串. 反引号:``,用于定义多行字符串,内部会原样解析. 示例: // 单行 "心有猛虎,细嗅蔷薇" // 多行 ` 大风歌 大风起兮云飞扬. 威加海内兮归故乡. 安得猛士兮守四方! ` 字符串支持转义

  • Go语言中循环语句使用的示例详解

    目录 一.概述 1. 循环控制语句 2. 无限循环 二.Go 语言 for 循环 1. 语法 2. for语句执行过程 3. 示例 4. For-each range 循环 三.循环嵌套 1. 语法 2. 示例 四.break 语句 1. 语法 2. 示例 五. continue 语句 1. 语法 2. 示例 六.goto 语句 1. 语法 2. 示例 一.概述 在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句. 循环程序的流程图: Go 语言提供了以下几种类型循环

  • C语言中进程间通讯的方式详解

    目录 一.无名管道 1.1无名管道的原理 1.2功能 1.3无名管道通信特点 1.4无名管道的实例 二.有名管道 2.1有名管道的原理 2.2有名管道的特点 2.3有名管道实例 三.信号 3.1信号的概念 3.2发送信号的函数 3.3常用的信号 3.4实例 四.IPC进程间通信 4.1IPC进程间通信的种类 4.2查看IPC进程间通信的命令 4.3消息队列 4.4共享内存 4.5信号灯集合 一.无名管道 1.1无名管道的原理 无名管道只能用于亲缘间进程的通信,无名管道的大小是64K.无名管道是内

  • C语言中枚举与指针的实例详解

     C语言中枚举与指针的实例详解 总结一下, 定义枚举,用typedef enum关键字, 比如 typedef enum{Red,Green,Blue} Color3; 枚举到数值的转换,如果没有指定代表数值就是从0开始算, 比如 Color3 c=Red; printf("%d",c);会显示0, 除非指定 如typedef enum{Red=3,Green=5,Blue=10} Color3; 关于类型指针的定义, 定义的时候在变量名左边加*代表此变量只是一个空指针而已, 若需要赋

  • C语言中关于动态内存分配的详解

    目录 一.malloc 与free函数 二.calloc 三.realloc 四.常见的动态内存的错误 [C语言]动态内存分配 本期,我们将讲解malloc.calloc.realloc以及free函数. 这是个动态内存分配函数的头文件都是 <stdlib.h>. c语言中动态分配内存的函数,可能有些初学c语言的人不免要问了:我们为什么要通过函数来实现动态分配内存呢? 首先让我们熟悉一下计算机的内存吧!在计算机的系统中大致有这四个内存区域: 1)栈:在栈里面储存一些我们定义的局部变量以及形参(

  • Go语言中的流程控制结构和函数详解

    这小节我们要介绍Go里面的流程控制以及函数操作. 流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑.Go中流程控制分三大类:条件判断,循环控制和无条件跳转. if if也许是各种编程语言中最常见的了,它的语法概括起来就是:如果满足条件就做某事,否则做另一件事. Go里面if条件判断语句中不需要括号,如下代码所示: 复制代码 代码如下: if x > 10 {     fmt.Println("x is greater than 10&

随机推荐