问题背景
写程序的时候经常要定义这样一个数组,要前面程序运行后才能知道要定义数组的大小。
C99之可变长度数组(VLA)
C99:
1994年,由ANSI/ISO联合委员会开始修订C标准
1999年,1994年对C语言的修订引出了ISO 9899:1999的发表,它通常被称为C99
C11:
2011年,国际标准化组织(ISO)和国际电工委员会(IEC) 旗下的C语言标准委员会(ISO/IEC JTC1/SC22/WG14)正式发布了C11标准
c99标准中,新增了可变长度数组:Variable-length array (VLA);C11中VLA变为可选项,不是语言必备的特性。
关于变长数组
变长数组中的“变”不是指可以修改已创建数组的大小,一旦创建了变长数组,它的大小则保持不变。这里的“变”指的是:在创建数组时,可以使用变量指定数组的长度。(普通数组只能用常量或常量表达式指定数组的长度)
- 变长数组VLA只能是局部变量数组
- 变长数组VLA不能在定义的时候进行初始化
- 变长数组VLA必须是自动存储类别,即不能使用extern或static存储类别说明符
- 变长数组VLA不等于动态数组,本质还是静态数组,也就是说,数组的长度在变量的整个生命周期中是不可变的
- 由于变长数组只能是局部变量,且必须是自动存储类别,因此变长数组分配在栈上
- 可变长数组对于多维数组也适用(如array[a][b] )
示例:
#include <stdio.h>
int main(void)
{
int a=0;
int b=0;
scanf("%d %d",&a,&b);
char array[a][b];
printf("sizeof(array)=%d\n",sizeof(array));
return 0;
}
上述代码需在支持C99标准的编译器上才行(注意,VS系列编译器均不支持该特性)
我编译成功用的gcc版本号:
根据上面关于数组的几项注意点,下面列出几种错误的示例:
int a=2;
int b=3;
char array1[a][b] = {1,2,3,4,5,6}; //错误,变长数组VLA不能在定义的时候进行初始化
char array2[a][b] = {{1,2,3},{4,5,6}}; //错误,变长数组VLA不能在定义的时候进行初始化
static char array3[a][b]; //错误,变长数组VLA必须是自动存储类别
关于如果是const变量做数组长度,下面还有几种情况需要思考:
1、在函数体外部,全局数组长度用const类型全局变量,是否可行? – 答:可以。
#include <stdio.h>
const int len = 10;
char array[len];
void main()
{
printf("sizeof(array)=%d\n",sizeof(array));
}
2、在函数体外部,static 全局数组长度用const类型全局变量,是否可行? – 答:可以。
#include <stdio.h>
const int len = 10;
static char array[len];
void main()
{
printf("sizeof(array)=%d\n",sizeof(array));
}
3、在函数体内部,static 局部数组长度用const类型局部变量,是否可行? – 答:可以。
#include <stdio.h>
void main()
{
const int len = 10;
static char array[len];
printf("sizeof(array)=%d\n",sizeof(array));
}
4、在函数体内部,局部数组长度用const类型局部变量,是否可行? – 答:可以。
#include <stdio.h>
void main()
{
const int len = 10;
char array[len];
printf("sizeof(array)=%d\n",sizeof(array));
}
总结:const变量不能直接改变,用其定义数组长度实际上已经不再是变长数组了。
动态内存分配malloc实现动态数组
C语言里,所有变量空间都是在程序运行之初向系统申请的,包括指针,除了一些动态申请方式如malloc函数。没有申请的空间系统是不允许读写的。在C99标准之前的C89,C90,如果一个数组大小是变量定义,则在程序运行前不能确定数组大小,也就无法申请,故不允许。所以,解决的办法便是通过malloc函数,即
int a[n];
可改为
int* const a = (int*)malloc(sizeof(int)*n);
这样a变量就完全可以当作一个数组直接使用了,包括a[1]之类的。因为“[]”中括号运算符做的只是偏移其内的地址数并取值。如:
a[1]
等价于
*(a + 1)
而const修饰符在星号之后,则表示指针在被声明后指向内容可以变,指向地点不能变,即只能指向这个获取的空间,完全符合数组的性质
const可以去掉,但要保证使用时不改变a的指向。
const是一个C语言(ANSI C)的关键字,具有着举足轻重的地位。它限定一个变量不允许被改变,产生静态作用。使用const在一定程度上可以提高程序的安全性和可靠性。
malloc实现一维动态数组p[m]:
示例:
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
int main(void)
{
int m;
scanf("%d", &m);
int* const p = (int*)malloc(m*(sizeof(int)));
memset(p, 0, m);//初始化,每个元素都为零
int i;
for (i=0;i<m; i++)//数组赋值
{
p[i] = i;
}
for (i = 0; i <m; i++)//打印数组
{
printf("%d,", p[i]);
}
free(p);
return 0;
}
malloc实现二维动态数组p[m][n]:
示例:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int main(void)
{
int m, n;
scanf("%d %d", &m,&n);
int **p;
p = (int**)malloc(m*(sizeof(int*)));//二级指针所在地址申请内存
int i, j;
for (i = 0; i<m; i++)
p[i] = (int*)malloc(sizeof(int)*n);//一级指针所在地址申请内存
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
p[i][j] = i + j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
printf("%d %p ", p[i][j], &p[i][j]); //输出每个元素及地址,每行的列与列之间的地址时连续的,行与行之间的地址不连续
}
printf("\n");
}
for (i = 0; i < m; i++) free(p[i]);
free(p);
return 0;
}
测试示例:
变长数组VLA对比动态内存分配malloc
变长数组是自动存储类型。因此,程序在离开变长数组定义所在的块、函数时,变长数组占用的内存空间会被自动释放,不必使用free()。另一方面,用malloc()创建的数组不必局限在一个函数内访问。
变长数组内存分配是在栈上,使用malloc内存分配在堆上。文章来源:https://www.toymoban.com/news/detail-624432.html
0长度数组实现可变长数组
详见另一篇博文:https://blog.csdn.net/weixin_44788542/article/details/125858372文章来源地址https://www.toymoban.com/news/detail-624432.html
到了这里,关于C语言的变长数组的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!