问题 使用const int定义数组的大小


当我尝试运行它时,它给出了一个错误,说明变量中的值 a 不是恒定的。这对我来说没有意义,因为我明确地做了变量 a 不变。数组的大小是否必须更加恒定?只有意义 #define a 5,或将其初始化为 int arr[5] 或使用 malloc?我做了什么错了?

int main{

   const int a = 5;
   int i;
   int arr [a];

   for (i = 0; i < 5; i++) {
      arr[i] = i * 2;
   }

  printf("%d", arr[1]);
  return 0;
}

3741
2018-01-25 16:39


起源

你假设可用的替代品主要是 #define 要么 malloc 是正确的 - 选择其中一个选项来修复它。 l3x的答案很好地解释了原因。 - GrandOpener


答案:


在C中, const 应该读作 只读。它没有定义编译时间。

const int a = 5;

这里 a是的  根据需要的常量表达式 C标准

6.7.9初始化
  4具有静态或线程存储持续时间的对象的初始化程序中的所有表达式都应是常量   表达式或字符串文字。

因此错误表明您正在使用C89 / C90编译器。您可以阅读用户的输入 a 并声明一个 可变长度数组,这是一个C99功能,具有自动存储持续时间。

运用 #define 是另一种方式。但它只是一个文本替换,并定义了一个具有自动存储持续时间的数组。它与定义相同 int arr[5]; 你自己。

如果要在动态存储上分配内存(通常称为“堆”),则必须使用 malloc() 家庭功能,在你打电话之前,它将在整个程序执行期间保持一生 free() 在上面。

(注意这种行为 const 仅在C中.C ++与此不同,并且可以按预期工作)。


如果我在C89中编译代码,它会失败:

#include <stdio.h>

int main(){

   const int a = 5;
   int i;
   int arr [a];

   for (i = 0; i < 5; i++) {
      arr[i] = i * 2;
   }

  printf("%d", arr[1]);
  return 0;
}

$ gcc -Wall -Wextra -std=c89 -pedantic-errors test.c
test.c: In function âmainâ:
test.c:7:4: error: ISO C90 forbids variable length array âarrâ [-Wvla]
    int arr [a];
    ^

因为C89不支持VLA(虽然gcc支持它 延期 即使在C89 / C90)。因此,如果您使用的是不支持C99的编译器,则无法使用VLA。 例如,visual studio不完全支持所有C99和C11功能。虽然, Visual Studio 2015支持大多数C99功能,VLA不是其中之一。

但是相同的代码在C99和C11中编译没有任何问题:

$ gcc -Wall -Wextra -std=c99 -pedantic-errors t.c
$ gcc -Wall -Wextra -std=c11 -pedantic-errors t.c

这是因为在C99中添加了可变长度数组(VLA)。请注意,在C11标准中,VLA已经成为可选项。因此,实现可能不支持C11中的VLA。 你需要测试 __STDC_NO_VLA__ 检查您的实现是否不支持VLA。

6.10.8.3条件特征宏

__STDC_NO_VLA__
      整数常量1,用于表示实现不支持可变长度数组或可变   修改过的类型

我个人不使用VLA,因为如果数组大小相当大,则无法轻易找到分配失败。例如。

size_t size = 8*1024;
int arr[size];

在上面的片段中,如果 arr 分配失败,直到运行时才会知道它。什么是“足够小”的大小,内存分配取决于平台。所以在一台机器上,1MB的分配可能会成功,另一台可能会失败,更糟糕的是,没有办法抓住这个失败。

因此,VLA的使用是有限的,并且只能用于您知道在给定平台上始终成功的小型阵列。但是,我只需对数组大小进行硬编码并处理边界条件。


9
2018-01-25 16:43



或者如果你真的想要数组大小硬编码,请使用 #define 指令叫 arraySize 或类似的东西。 - rlam12
我不明白为什么你只提到了VLA的传递参考。这不是OP想要做的吗?如果她正在使用MSVC,即使2015版本也不支持VLA。她甚至在问题中提到了你的方法,所以清楚地理解它们。 - Weather Vane
@WeatherVane你是对的,它需要更多的解释。我做了更新。谢谢。 - P.P.


也许使用枚举来定义值 a

enum { a = 5 };
int arr [a];

也许这不是枚举的意图,但枚举的成员是最接近C中常量的东西。不同于使用定义所有内容的常见做法 #define,知名度 a 受范围限制,这里它是相同的 arr


1
2017-12-12 01:22



真棒的想法!!! - outoftime


一个 const - 限定变量与a不同 不断表达;常量表达式在编译时已知其值,而a const - 限定变量(通常)不会(即使看起来应该如此)。

请注意,在C99及更高版本中,可以声明 可变长度数组,直到运行时才知道数组大小。您必须使用C99或更高版本的编译器,并且鉴于该功能在2011标准中是可选的,您必须检查功能宏以查看VLA是否可用:

static const int a = 10; // a is not a constant expression

#if defined( __STDC__ ) && defined ( __STDC_VERSION__ ) && __STDC_VERSION__ >= 199901L && !defined( __STDC_NO_VLA__ ) 
/**
 * VLAs are available in this environment
 */
#define USE_VLA 1
#endif

#ifdef USE_VLA
   int arr[a];
#else
  /**
   * VLAs are not available, either because it's a pre-1999 implementation,
   * or it's a post-2011 implementation that does not support optional
   * VLAs.  We'll have to use dynamic memory allocation here, meaning we'll
   * also need an explicit free call when we're done with arr 
   */
  int *arr = malloc( sizeof *arr * a );
#endif
...
  do_something_interesting_with( a );
...
#ifndef USE_VLA
  free( a );
#endif

至少在最近,微软的C编译器不支持VLA。他们一直在添加一些C99功能,例如混合声明和代码,因此最新版本可能支持VLA。我不知道。


0
2018-01-25 17:09