C语言的变长数组

问题背景

写程序的时候经常要定义这样一个数组,要前面程序运行后才能知道要定义数组的大小。

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变为可选项,不是语言必备的特性。

关于变长数组

变长数组中的“变”不是指可以修改已创建数组的大小,一旦创建了变长数组,它的大小则保持不变。这里的“变”指的是:在创建数组时,可以使用变量指定数组的长度。(普通数组只能用常量或常量表达式指定数组的长度)

  1. 变长数组VLA只能是局部变量数组
  2. 变长数组VLA不能在定义的时候进行初始化
  3. 变长数组VLA必须是自动存储类别,即不能使用extern或static存储类别说明符
  4. 变长数组VLA不等于动态数组,本质还是静态数组,也就是说,数组的长度在变量的整个生命周期中是不可变的
  5. 由于变长数组只能是局部变量,且必须是自动存储类别,因此变长数组分配在栈上
  6. 可变长数组对于多维数组也适用(如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内存分配在堆上。

0长度数组实现可变长数组

详见另一篇博文:https://blog.csdn.net/weixin_44788542/article/details/125858372

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吾爱技术圈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值