【前言】经常看到C语言里的两个数组,总结一下。

一、柔性数组

  参考:https://www.cnblogs.com/veis/p/7073076.html

#include<stdio.h>
typedef struct _SoftArray{
int len;
int array[];
}SoftArray; int main()
{
int len = 10; printf("The struct's size is %d\n",sizeof(SoftArray));
}

  

  我们可以看出,_SoftArray结构体的大小是4,显然,在32位操作系统下一个int型变量大小刚好为4,也就说结构体中的数组没有占用内存。为什么会没有占用内存,我们平时用数组时不时都要明确指明数组大小的吗?但这里却可以编译通过呢?这就是我们常说的动态数组,也就是柔性数组。

1、什么是柔性数组?

  柔性数组既数组大小待定的数组。C语言中结构体的最后一个元素可以是大小未知的数组,也就是所谓的0长度,所以我们可以用结构体来创建柔性数组。

2、柔性数组有什么用途 ?

  它的主要用途是为了满足需要变长度的结构体,为了解决使用数组时内存的冗余和数组的越界问题。

3、用法 :

  在一个结构体的最后 ,申明一个长度为空的数组,就可以使得这个结构体是可变长的。对于编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量, 数组名这个符号本身代 表了一个不可修改的地址常量 (注意:数组名永远都不会是指针! ),但对于这个数组的大小,我们可以进行动态分配,对于编译器而言,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是代表了一个偏移量,代表一个不可修改的地址常量!

  对于柔性数组的这个特点,很容易构造出变成结构体,如缓冲区,数据包等等:

    typedef struct _SoftArray

    {

        Int len;

      int array[];

    }SoftArray;

  这样的变长数组常用于网络通信中构造不定长数据包,不会浪费空间浪费网络流量,比如我要发送1024字节的数据,如果用定长包,假设定长包的长度为2048,就会浪费1024个字节的空间,也会造成不必要的流量浪费。

4、举例

#include<stdio.h>
#include<malloc.h>
//其中有两个成员:一个是len,代表数组的长度;一个是array[],代码数组的内容
typedef struct _SoftArray{
int len;
int array[];
}SoftArray;
int main()
{
int len=10,i=0;
//分配空间的格式。此时softarray大小仍然为4
SoftArray *p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*len);
p->len=len; for(i=0;i<p->len;i++)
{
p->array[i]=i+1;
}
for(i=0;i<p->len;i++)
{
printf("%d\n",p->array[i]);
} free(p); return 0;
}

  

  这代码的作用是用柔性数组动态创建数组并输出数组内容,这里我就直接解释解释这两句代码:

SoftArray* p = (SoftArray*)malloc(sizeof(SoftArray) + sizeof(int) *10);

 p->len = 10;

 第一句,主要是根据你要定义的数组长度和数据类型以及柔性数组本身的大小来开辟一块内存空间给柔性数组p,第二个是定义len的长度,便于确定循环打印输出是循环的次数。

5、柔性数组在“不确定数组大小”中的应用 

 对不确定len值大小的数组,使用了数组的方法。若不定义柔性数组,定义普通数组len需要确定的值!如10,11...
#include<stdio.h>
#include<malloc.h>

typedef struct _SoftArray{
int len;
int array[];
}SoftArray; //打印输出斐波那契数列
void printfln(SoftArray *p,int len)
{
int i;
for(i=0;i<len;i++) //循环进行打印输出
{
printf("%d\n",p->array[i]);
}
} //动态生成斐波那契数列
void create(int len)
{
int i; SoftArray * p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*len); //声明结构体指针p,动态申请内存,大小为结构体大小+10个int型大小
//对不确定len值大小,使用了数组的方法。若不定义柔性数组,定义普通数组len需要确定的值!如10,11...
for(i=0;i<len;i++) //循环进行数组赋值
{
if( i <= 1 )
{
p->array[i] = 1;
}else if( i >= 2 )
{
p->array[i] = p->array[i-1] + p->array[i-2];
}else
{
printf("DAMAGE: before Normal block or after Normal block");
return (-1);
} }
printfln(p,len);
free(p);
} //主函数
int main()
{
int i=0;
int len;
printf("请输入生成斐波那契数列的行数:");

scanf("%d",&len);
//将一个不确定值传入了函数
create(len); return 0;
} 

二、动态数组

  动态数组,即根据实时变化,可以扩大数组大小。而这个功能的实现需要用到指针和malloc和realloc函数
    int *a = (int*)malloc(10*sizeof(int));那么 a就相当于一个有10个元素的数组。当数据量超过10个放不下的时候,利用
    a = (int*)realloc(a, 20*sizeof(int));//意思是把a的大小增加到20,而保持原来已有的数据不变。
  上面的函数要包含:#include<stdlib.h> #include<malloc.h> 或#include<alloc.h>

举例说明:

#include<stdio.h>
#include<stdlib.h>
void DimensionalVector(){
int n, i;
int *arr;
//输入不定的值,体现了数组与指针的关系
scanf("%d",&n);
arr = (int*)malloc(sizeof(int)*n); for (i = 0; i < n; i++)
arr[i] = i;
for (i = 0; i < n; i++)
printf("%d\t",arr[i]);
} int main(){
DimensionalVector(); return 0;
}

  体现了数组与指针的关系,可具体参考数组与指针的转换关系。

三、二者的区别

  柔性数组是利用结构体,动态数组使用了指针与数组的关系;

  前者在创建之后,利用p->array[]来访问每一个值,后者直接利用p[]来访问每一个值;

四、malloc和calloc,relloc

  1、对于用malloc分配的内存区间,如果原来没有被使用过,则其中的每一位可能都是0;反之, 如果这部分内存空间曾经被分配、释放和重新分配,则其中可能遗留各种各样的数据。也就是说, 在使用它之前必须先进行初始化(可用memset函数 对其初始化为0);

  2、但调用calloc()函数分配到的空间在分配时就已经被初始化为0了;

  3、rellocc函数用于修改一个原先已经分配的内存块的大小,可以使一块内存的扩大或缩小。当起始空间的地址为空,即*ptr = NULL,则同malloc。当*ptr非空:若nuw_size < size,即缩小*ptr所指向的内存空间,该内存块尾部的部分内存被拿掉,剩余部分内存的原先内容依然保留;若nuw_size > size,即扩大*ptr所指向的内存空间,如果原先的内存尾部有足够的扩大空间,则直接在原先的内存块尾部新增内存,如果原先的内存尾部空间不足,或原先的内存块无法改变大小,realloc将重新分配另一块nuw_size大小的内存,并把原先那块内存的内容复制到新的内存块上。因此,使用realloc后就应该改用realloc返回的新指针。

  malloc空间分配算法可参考另一篇我的博文:https://www.cnblogs.com/huangfuyuan/p/9190371.html

C语言柔性数组和动态数组的更多相关文章

  1. [C] 在 C 语言编程中实现动态数组对象

    对于习惯使用高级语言编程的人来说,使用 C 语言编程最头痛的问题之一就是在使用数组需要事先确定数组长度. C 语言本身不提供动态数组这种数据结构,本文将演示如何在 C 语言编程中实现一种对象来作为动态 ...

  2. JS 索引数组、关联数组和静态数组、动态数组

    JS 索引数组.关联数组和静态数组.动态数组 数组分类: 1.从数组的下标分为索引数组.关联数组 var ary1 = [1,3,5,8]; //按索引去取数组元素,从0开始(当然某些语言实现从1开始 ...

  3. "《算法导论》之‘队列’":队列的三种实现(静态数组、动态数组及指针)

    本文有关栈的介绍部分参考自网站数据结构. 1. 队列  1.1 队列的定义 队列(Queue)是只允许在一端进行插入,而在另一端进行删除的运算受限的线性表. (1)允许删除的一端称为队头(Front) ...

  4. solidity定长数组和动态数组

    固定长度的数组 固定长度数组声明 直接在定义数组的时候声明固定长度数组的值: uint[5] fixedArr = [1,2,3,4,5]; 可通过数组的length属性来获得数组的长度,进而进行遍历 ...

  5. go语言之切片即动态数组

    切片和数组的类型有什么不一样,我们可以打印一下,就可以知道两者的区别了,数组是容量的,所以中括号中有容量,切片的动态数组,是没有容量,这是数组和切片最大的区别 test8_4 := [20] int ...

  6. C语言中怎么求动态数组大小

    先来个简单的样例 int a[] = {1,2,3}; int arr_len = 0; arr_len = sizeof(a)/sizeof(int); 解释:sizeof() keyword是求出 ...

  7. C语言数组:C语言数组定义、二维数组、动态数组、字符串数组

    1.C语言数组的概念 在<更加优美的C语言输出>一节中我们举了一个例子,是输出一个 4×4 的整数矩阵,代码如下: #include <stdio.h> #include &l ...

  8. C/C++静态数组与动态数组的区别

    简介 以下三行代码有什么区别? int a[10]; int *a = (int*)malloc(sizeof(int)*10); int *a = new int[10]; 第一行代码定义a为包含1 ...

  9. "《算法导论》之‘栈’":栈的三种实现(静态数组、动态数组及指针)

    本文有关栈的介绍部分参考自网站数据结构. 1. 栈  1.1 栈的定义 栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表. (1)通常称插入.删除的这一端为栈顶(Top),另一端称为栈底( ...

随机推荐

  1. DICOM医学文件的解析

    最近导师一直让做智慧医疗的一个项目,这里面涉及到DICOM格式的文件处理,在这里分享一下自己学到的关于DCM文件的一些内容. DICOM DICOM(DigitalImaging andCommuni ...

  2. 2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest (9/12)

    $$2015-2016\ ACM-ICPC,\ NEERC,\ Northern\ Subregional\ Contest$$ \(A.Alex\ Origami\ Squares\) 签到 //# ...

  3. 【洛谷 p3383】模板-线性筛素数(数论)

    题目:给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内).(N<=10000000,M<=100000) 解法:1.欧拉筛O(n),数组近乎100KB:2.( ...

  4. HDU - 2825 Wireless Password (AC自动机+状压DP)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2825 题意:给一些字符串,构造出长度为n的字符串,它至少包含k个所给字符串,求能构造出的个数. 题解: ...

  5. Happy 2006 POJ - 2773 容斥原理+二分

    题意: 找到第k个与m互质的数 题解: 容斥原理求区间(1到r)里面跟n互质的个数时间复杂度O(sqrt(n))- 二分复杂度也是O(log(n)) 容斥原理+二分这个r 代码: 1 #include ...

  6. hdu5305 Friends

    Problem Description There are n people and m pairs of friends. For every pair of friends, they can c ...

  7. WSL2 新建dotnet core mvc项目

    我们知道dotnet sdk会有很多命令,但在我们完全不知道如何去使用哪个命令. 我们使用dotnet -h进行查看: 我们看到SDK的new命令,但是new命令又如何使用呢? 我们再次使用帮助: 可 ...

  8. 【史上最全】Hadoop 核心 - HDFS 分布式文件系统详解(上万字建议收藏)

    1. HDFS概述 Hadoop 分布式系统框架中,首要的基础功能就是文件系统,在 Hadoop 中使用 FileSystem 这个抽象类来表示我们的文件系统,这个抽象类下面有很多子实现类,究竟使用哪 ...

  9. SpringCloud @RefreshScope标注的Bean在生命周期中怎么样的?

    @RefreshScope 前言 该文章是由上一篇引申而来的,上一篇文章描述了Nacos是怎么触发配置刷新的,接着来写有关@RefreshScope的一些东西,都是由DEBUG而来 上一篇 文章概览 ...

  10. Netty(五)Netty 高性能之道

    4.背景介绍 4.1.1 Netty 惊人的性能数据 通过使用 Netty(NIO 框架)相比于传统基于 Java 序列化+BIO(同步阻塞 IO)的通信框架,性能提升了 8 倍多.事 实上,我对这个 ...