前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅析变长数组(VLA)和动态数组

浅析变长数组(VLA)和动态数组

作者头像
休辞醉倒
发布2019-07-23 17:24:20
1.7K0
发布2019-07-23 17:24:20
举报
文章被收录于专栏:休辞醉倒休辞醉倒

前天实训听见几位推免的大佬聊面试中出现了动态数组,而我们所学并没有涉及到动态数组,遂翻起了尘封已久的《C语言程序设计现代方法》以及《C Primer Plus》,果然大神们写书都很全面(厚),后悔当初没有认真拜读。

一、C99中的变长数组

下面程序用到了变长数组

#include<stdio.h>

int main() { int i,n;

printf(“How many numbers do you want to reverse?”); scanf(“%d”,&n);

int a[n]; //只有C99支持n决定数组范围

printf(“Enter %d numbers: “,n); for(i=0;i<n;i++) { scanf(“%d”,&a[i]); } printf(“In reverse order:”); //倒序输出数组 for(i=n-1;i>=0;i–) printf(” %d”,a[i]); printf(“\n”);

return 0;

}

上面程序中的数组a是一个变长数组(variable-length array,简称VLA)。变长数组的长度是在程序执行时计算的,而不是在程序编译时计算的。变长数组的主要优点是程序员不必在构造数组时随便给定一个长度,程序在执行时可以准确地计算出所需的元素个数。如果让程序员来制定长度,数组可能过(浪费)或过短(导致程序出错)。

变长数组的长度不一定要用变量来指定,任意表达式(可以含运算符)都可以,例如:

int a[3*i+5];

int b[j+k];

现在我们已经知道什么是变长数组了,但是,假如,变长数组作为形式参数,到底应该如何写呢?

现在,假设有一函数

int sum_array( int a[n] , int n )

{

……

}

编译器会在遇到int a[n]时显示出错信息,因为此前它没有见过n。

下面给出正确的函数原型:

int sum_array(int n , int a[n] ); //version 1

int sum_array(int n , int a[*] ); //version 2

一般来说,变长数组形式参数的长度可以是任意表达式。例如,假设我们要编写一个函数来连接两个数组a和b,要求先复制a的元素,再复制b的元素,把结果写入第三个数组c:

int concatenate(int m , int n , int a[m] , int b[n] , int c[m+n] )

{

}

数组c的长度是a和b的长度之和。这里用于指定数组c长度的表达式只用到了另外两个参数;但一般来说,该表达式可以使用函数外部的变量,甚至可以调用其他函数。

敲黑板!!!重点来了

变长数组的大小不会变化,变长数组中的“变”并不表示在创建数组后还可以修改它的大小。变长数组的大小在创建后就是保持不变的。“变”的意思是说其维大小可以用变量来指定。

变长数组允许动态分配存储单元,这表示可以在程序运行时指定数组的大小。常规的C数组是静态存储分配的,也就是说在编译时数组的大小就已经确定。

接下来要说的动态数组,才是大小会变化的数组。

二、动态数组

现在我们讨论C语言中如何实现动态数组。请系好安全带,加速了加速了。

基本思路就是使用malloc()库函数(内存分配)来得到一个指向一大块内存的指针。然后,像引用数组一样引用这块内存,其机理就是一个数组下标访问可以改写为一个指针加上偏移量。

1.使用malloc函数为数组分配存储空间

假设正在编写的程序需要n个整数构成的数组,这里的n可以在程序执行期间计算出来。首先,声明一个指针变量:

int *a;

一旦n的值已知了,就让程序调用malloc函数为数组分配存储空间:

a=malloc( n * sizeof(int) );

一旦a指向动态分配的内存块,就可以忽略a是指针的事实,可以把它作为数组的名字。这都要感谢C语言中数组和指针的紧密关系。例如,可以使用下列循环对a指向的数组进行初始化:

for ( i=0 ; i<n ; i++ )

a[i]=0;

当然,用指针算数运算取代下标操作来访问数组元素也是可行的。

2.使用calloc函数为数组分配存储空间

calloc函数在<stdlib.h>中具有如下所示的原型:

void * calloc ( size_t nmemb , size_t size );

calloc函数为nmemb个元素的数组分配内存空间,其中每个元素的长度都是size个字节。如果要求的空间无效,那么此函数返回空指针。在分配了内存之后,calloc函数会通过把所有位设置为0的方式进行初始化。例如下列calloc函数调用为n个整数的数组分配存储空间,并且保证所有整数初始均为零:

a=calloc(n,sizeof(int));

3.使用realloc函数调整数组的大小

一旦为数组分配完内存,稍后可能会发现数组过大或过小。realloc函数可以调整数组的大小使它更适合需要。<stdlib.h>中的realloc原型:

void * realloc ( void *ptr, size_t size );

当调用realloc函数时,ptr必须指向先前通过malloc、calloc或realloc的调用获得的内存块。size表示内存块的新尺寸,新尺寸可能会小于或大于原有尺寸。虽然realloc不要求ptr指向正在用作数组的内存,但实际上通常是这样的。

在要求减少内存块大小时,realloc函数应该“在原先的内存块上”直接进行缩减,而不需要移动存储在内存块中的数据。同理,扩大内存块时也不应该对其进行移动。如果无法扩大内存块(因为内存块后面的字节已经用于其他目的),realloc函数会在别处分配新的内存块,然后把旧块中的内容复制到新块中。所以,一旦realloc函数返回,一定要对指向内存块的所有指针进行更新,因为realloc函数可能会使内存块移动到了其他地方。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、C99中的变长数组
  • 二、动态数组
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档