多年老c++程序员在静态数组这里翻船了

cpp加油站
• 阅读 1580

事情的起因

事情是这样子滴,有一次我在代码评审的时候,发现有同事想使用运行时才能够获取到的值,去改变一个静态数组的元素个数,我当时就很诧异,因为我心里知道这样是不可行的,静态数组的元素个数在编译时就需要是固定不变的,一般只能是常量或者宏定义,否则编译就不能通过。

但是当时我提出来以后,把原因说了,包括写出这个代码的人和另外一位同事都没理解,弄得我有点怀疑自己了,难道是我搞错了?

我左思右想,最后我写了下面的代码来证实一下:

#include <iostream>
using namespace std;

int get()
{
    int size = 0;
    cout << "please input a num:";
    cin >> size;
    return size;
}

int main()
{
    int size = 1000;
    size = get();
    int arr[size] = {0};

    cout << "arr's size is " << sizeof(arr)/sizeof(arr[0]) << endl;

    return 0;
}

我打心底认为,这段程序肯定是编译不通过的,但是结果打脸了。编译后执行显示如下:

please input a num:10000
arr's size is 10000

不仅编译通过了,而且数组大小还在运行时修改了,可是我明明定义的是一个静态数组呀,而且就算我这里不给size赋初始值1000,结果也还是一样的。

探索的过程

简直是见了鬼了,我把代码看了又看,认为是我代码写错了,但是这么简单的一段代码,我不可能写错呀。后来我突然想到,会不会是有了新的语法?

因为我现在的gcc编译器,大家都知道是7.1.0的版本,基本上连c++17都能支持了,我就试了一下之前保留的gcc4.1.2的版本,结果报错啦,如下:

test.cpp: In function ‘int main()’:
test.cpp:15: 错误:可变大小的对象 ‘arr’ 不能被初始化

所以很显然,我的记忆没有错误,之前静态数组的元素个数它就必须是个不可变的,否则编译就会出错。

然后我又看了下生产上用的编译器,是gcc4.8.5的版本,它也是支持c++11的,难道这个新的特性是c++11支持的吗?然后我去cppreference把c++11的新特性从头到尾翻了一遍,并没有对这个修改有说明,并且网上搜索,所有的文章都在说c和c++想使用变长数组,就必须要使用动态数组,我一度陷入了僵局,但是我并没有死心,继续探索。

后来我忽然想到,假如不是c++的新特性,那是不是c语言的新特性呢,想到这里,我把代码做了如下修改:

#include <stdio.h>

int get()
{
    int size = 0;
    printf("please input a num:");
    scanf("%d", &size);
    return size;
}

int main()
{
    int size = 1000;
    size = get();
    int arr[size] = {0};

    printf("arr's size is %d\n", sizeof(arr)/sizeof(arr[0]));

    return 0;
}

然后直接使用gcc命令编译,而没有使用g++,结果跟上面那段代码是一模一样的,到这里我大致上就明白了,这就是c语言里面的新特性。

欣喜的找到了结果

最后我在cppreference这个链接里面看到了对于c99的说明:

  1. 新特性: Bool 、 long long 、 stdint.h 、 inttypes.h 、 restrict 、复合字面量、变长度数组、伸缩数组成员、指派初始化器、 fenv.h 、变参数宏、复数、 func 、十六进制浮点格式( %a )、 lconv 的货币格式化、 isblank 、窄与宽字符串字面量的连接、枚举的尾逗号、类函数宏的空参数、 STDC* pragma 、 va_copy 、 tmpnam 的空返回、 setvbuf 中的空指针、 printf 的 hh 与 ll 长度指定符、 snprintf 、 _Exit 、 tgmath.h 、仿 POSIX strftime 说明符
  2. 来自 C++ : inline 、声明与代码混合、 for 循环的 init 子句中的声明、 **//** 注释、源代码中的通用字符名
  3. 移除隐式函数声明和隐式 int

看看,是不是明确说明了新特性是变长度数组,并且是c语言99年的标准,有点灯下黑了,以后如果再看到有人说c语言和c++的静态数组都只支持固定长度,要想变长就必须要使用malloc和new,就可以唾弃一下啦。

另外有一点需要注意的是,如果我们的场景真的是需要使用固定大小的数组,那么最好使用常量和宏定义,再不然,就使用c++11里面新增加的array。

点赞
收藏
评论区
推荐文章
Jacquelyn38 Jacquelyn38
1年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Peter20 Peter20
1年前
mysql中like用法
like的通配符有两种%(百分号):代表零个、一个或者多个字符。\(下划线):代表一个数字或者字符。1\.name以"李"开头wherenamelike'李%'2\.name中包含"云",“云”可以在任何位置wherenamelike'%云%'3\.第二个和第三个字符是0的值wheresalarylike'\00%'4\
Stella981 Stella981
1年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
1年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序selectfromtable_nameorderiddesc;2.按照指定(多个)字段排序selectfromtable_nameorderiddesc,statusdesc;3.按照指定字段和规则排序selec
Wesley13 Wesley13
1年前
PHP中的NOW()函数
是否有一个PHP函数以与MySQL函数NOW()相同的格式返回日期和时间?我知道如何使用date()做到这一点,但是我问是否有一个仅用于此的函数。例如,返回:2009120100:00:001楼使用此功能:functiongetDatetimeNow(){
Wesley13 Wesley13
1年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
helloworld_34035044 helloworld_34035044
7个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
京东云开发者 京东云开发者
2个月前
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究