【前言】经常看到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. Jenkins(2)docker容器中安装python3

    前言 使用docker安装jenkins环境,jenkins构建的workspace目录默认是在容器里面构建的,如果我们想执行python3的代码,需进容器内部安装python3的环境. 进jenki ...

  2. MDK中用C++开发STM32

    ​作者:良知犹存 转载授权以及围观:欢迎添加微信:Allen-Iverson-me-LYN 前言     最近想开发一段单片机的代码,代码本身有很多的重复元素,这重复定义的一些结构体使用起来有些繁琐, ...

  3. HDFS读写流程(转载)

    概述开始之前先看看其基本属性,HDFS(Hadoop Distributed File System)是GFS的开源实现.特点如下:    能够运行在廉价机器上,硬件出错常态,需要具备高容错性    ...

  4. 关于KMP算法的理解

    上次因为haipz组织的比赛中有道题必须用到KMP算法,因此赛后便了解了下它,在仔细拜读了孤~影神牛的文章之后有种茅塞顿开的感觉,再次ORZ. 附上链接http://www.cnblogs.com/y ...

  5. Codeforces Round #645 (Div. 2) D. The Best Vacation (贪心,二分)

    题意:一年有\(n\)个月,每月有\(d_{i}\)天,找出连续的\(x\)天,使得这\(x\)天的日期总和最大,任意一年都能选. 题解:首先要先贪心,得到:连续的\(x\)天的最后一天一定是某个月的 ...

  6. ElasticSearch 交互使用

    Curl 命令 # 建立索引 [root@dbtest01 ~]# curl -XPUT 'http://10.0.0.121:9200/test' # 插入数据 [root@dbtest01 ~]# ...

  7. Shell 元字符 & 变量

    Shell 介绍 ## 什么是程序 程序就是一组数据和代码逻辑集合的文件 ## 什么是进程 进程是程序的运行过程,也可以说是操作系统干活的过程,因为是操作系统负责控制硬件来运行应用程序 ps:进程与进 ...

  8. ElasticSearch 7.x 学习

    目录 ElasticSearch 7.x 一.前言 1.1.正向索引和倒排索引 1.1.1.正向索引 1.1.2.倒排索引 二.安装 三.ES 基本概念 3.1.索引 3.2.文档 3.4.mappi ...

  9. codefoeces 864B

    B. Polycarp and Letters time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  10. hdu5693D++游戏 区间DP-暴力递归

    主要的收获是..如何优化你递推式里面不必要的决策 之前的代码 这个代码在HDU超时了,这就对了..这个复杂度爆炸.. 但是这个思路非常地耿直..那就是只需要暴力枚举删两个和删三个的情况,于是就非常耿直 ...